Ok, so I have a question regarding the EventArgs that can be passed when an event is triggered. I am designing a small, basic search engine and have a class called Query that contains a method Search. When this method is called, I want to trigger an event which will pass the results to be storred in a variety of cache class instances (SizeBoundedCache and TimeBoundedCache). So I thought the best way to do this would be to use an event.
The delegate is declared like this ->
public delegate void CacheStoreDelegate(object sender, EventArgs e);
The rest of the code within the Query class relevant to this question is here (uses Linq) ->
public event CacheStoreDelegate AddToCache;
public virtual void OnQuery (EventArgs e)
{
if(AddToCache != null)
AddToCache(this, e);
}
public Query()
{
}
public Query(string queryString, OOP5.Provided.QueryOperator op)
{
//Access and set the terms array
this.Terms = OOP5.Provided.QueryUtils.GetTermsFromString(queryString);
this.Operator = op;
}
public static IEnumerable<string> Search (this SearchCore s, IQuery q)
{
// Accept a query and return IEnumerable<string> of
// all document IDs matching that query
if (q.Operator == QueryOperator.Any)
{
var GetAnyMatch = from single_query in q.Terms
group s.Search(single_query)
by s.documents.Keys
into results
where results.Count >= 1
select results[0];
this.OnQuery(GetAnyMatch);
return GetAnyMatch;
}
if (q.Operator == QueryOperator.All)
{
var GetAllMatch = from single_query in q.Terms
group s.Search(single_query)
by s.documents.Keys
into results
where results.Count >= q.Terms.Lengthselect results[0];
this.OnQuery(GetAllMatch);
return GetAllMatch;
}
}
All the cache classes will be notified whenever a search is called and I also need thme to receive the results.
Thanks so much in advance for the help. Also, if there is a more elegant way to do this that I am not thinking of, please chime in. Cheers!
You could create your own EventArgs implementation:
class QueryResultEventArgs : EventArgs
{
public IEnumerable<string> Results { get; private set; }
public QueryResultEventArgs(IEnumerable<string> results)
{
Results = results;
}
}
...
public delegate void CacheStoreDelegate(object sender, QueryResultEventArgs e);
...
this.OnQuery(new QueryResultEventArgs(GetAnyMatch));
Make a class of type CacheStoreEventArgs deriving from eventargs
public class CacheStoreEventArgs:eventargs
{
private IEnumerable<string> Data;//List<string> better
public IEnumerable<string> data
{
get { return Data; }
set { this.Data = value; }
}
public CacheStoreEventArgs(IEnumerable<string> NewData)
{
this.data = NewData;
}
}
then declare the event(use predefined generic one,so no need to declare one)
public event EventHandler<CacheStoreEventArgs> AddToCache;
inside your method search you call your method "On...."
public static IEnumerable<string> Search (this SearchCore s, IQuery q)
{
//after you get query result
CacheStoreEventArgs cs = new CacheStoreEventArgs(queryresultvariablehere);
//and call your method now with the instance of your derived eventargs class
OnQuery(cs);
}
public virtual void OnQuery (CacheStoreEventArgs e)
{
try
{
EventHandler<CacheStoreEventArgs> temp = AddToCache
if( temp != null)
temp(this,e);
}
catch(Exception ex)
{
//exception handling
}
}
Related
I need to add the following to several unrelated classes:
private MyClass myclass;
private EventHandler clicked;
public event EventHandler Clicked { ... }
private bool enabled;
public bool Enabled { ... }
private void HandleClicked(object sender, EventArgs e) { ... }
The problem is these classes are third-party and do not necessarily share the same immediate base class though they all eventually inherit from a class called View. Right now, I end up creating my own subclasses for each and copy-pasting the same code which leads to unnecessary duplication.
Any way to meaningfully refactor this?
One of the way is to use composition. Create class which will store all new events\properties\methods:
public class Properties
{
private MyClass myclass;
private EventHandler clicked;
public event EventHandler Clicked { ... }
private bool enabled;
public bool Enabled { ... }
private void HandleClicked(object sender, EventArgs e) { ... }
}
Then use Extension methods to expand required interface (i.e. classA)
public static class NewInterfaces
{
public static Properties Props(this classA)
{ /* lookup required properties, from some associative storage */ }
}
Usage will look like:
var inst = new classA();
inst.Prop.Enabled = !inst.Prop.Enabled;
Second way it still composition, but you will use wrapper for those:
public class Wrapper
{
private object _wrapped;
public Wrapper(classA obj)
{
_wrapped = obj;
}
public Wrapper(classB obj)
{
_wrapped = obj;
}
public int WrappedProperty
{
get
{
var instA = _wrapped as classA;
if (instA != null)
return instA.SomeProperty1;
var instB = _wrapped as classB;
if (instB != null)
return instB.SomeProperty2;
}
}
private MyClass myclass;
private EventHandler clicked;
public event EventHandler Clicked { ... }
private bool enabled;
public bool Enabled { ... }
private void HandleClicked(object sender, EventArgs e) { ... }
}
Second way allow you to create new hierarchy of wrapper which will contain elements without common base class.
Inheritance becomes problematic in time. I recommend using interfaces instead, you will have much more flexibility.
public interface INewInterfaces
{
event EventHandler Clicked;
bool Enabled { get; }
void HandleClicked(object sender, EventArgs e);
}
public class NewClassA : ClassA, INewInterfaces
{
//...
}
public class NewClassB : ClassB, INewInterfaces
{
//...
}
Edit 1:
If you are saying that ClassX's are very similar and you want to use the same HandleClicked implementation in all of these unrelated classes, you may use two other approaches.
1- Still inheritance
Create an interface and add all the common functions across the classes you want to use. This will put the ClassX's in the same family. And then create a class for general use.
public interface IExistingInterfaces
{
void SomeMethod();
}
public class NewClassA : ClassA, IExistingInterfaces
{
//Do nothing
}
public class NewClassB : ClassB, IExistingInterfaces
{
//Do nothing
}
public class MyClassForGeneralUse : IExistingInterfaces
{
private IExistingInterfaces _baseObject;
public MyClassForGeneralUse(IExistingInterfaces baseObject)
{
_baseObject = baseObject;
}
//Write proxy calls for IExistingInterfaces
public void SomeMethod()
{
_baseObject.SomeMethod();
}
//Add new methods here
public void HandleClicked(object sender, EventArgs e)
{
}
//...
//...
}
Not: The first part is Bridge Pattern and the second part is Decorator Pattern
2- Reflection
var propertyInfo = someObject.GetType().GetProperty("property name");
if (propertyInfo == null)
throw new Exception(string.Format("Property does not exist:{0}", condition.Property));
var propertyValue = propertyInfo.GetValue(someObject, null);
long longValue = (long)propertyValue;
//You can get methods in a smilar manner and execute with
result = methodInfo.Invoke(methodInfo, parametersArray);
But reflection may be overkill.
I was given a generic API class, that contains a custom event which always needs to be invoked by the main UI thread.
My job is to banish these invocation call from the custom class, to make it "painless".
It should be synchronized like the default events in WinForms (eg the Timer "Elapsed" event, which also needs no invocation when it published values to a text box)
Is it possible to solve this, since the custom class needs to know where to invoke?
Here's the (important part of the) code:
public class ContactSensorHelper
{
public event OnReleaseStateChanged ReleaseStateChanged;
public delegate void OnReleaseStateChanged(ContactSensorEventArgs e);
private ContactSensorEventArgs.ReleaseState recentReleaseState;
public void ReportStateChanged()
{
if (ReleaseStateChanged != null)
ReleaseStateChanged(new ContactSensorEventArgs()
{
State = recentReleaseState
});
}
public class ContactSensorEventArgs : EventArgs
{
//......
public ReleaseState State { get; set; }
//......
public enum ReleaseState
{
FullReleased,
PartlyReleased,
NotReleased
}
}
}
The call from main UI:
public void SensorInit()
{
//....
sensorHelper.ReleaseStateChanged += releaseStateChanged;
//....
}
private void releaseStateChanged(ContactSensorEventArgs e)
{
//example
textBox1.Text = e.State.ToString(); // Thread exception (obviously)
}
Does anybody have me a hint to start?
You could do this by using your own event calling, and storing a reference to the thread, when the event is attached.
With the event add/remove syntax, you can have the caller attach to the event like before, but internally you store a list, with a reference to the thread (using an AsyncOperation) and the delegate to be called (used a Tuple containing both in the example)
Below is an example. I tested it, and it worked as expected when testing, but you might have to add some locking of the list to make it thread safe in case events are added/removed simultaneously.
public class ContactSensorHelper:IDisposable
{
public delegate void OnReleaseStateChanged(ContactSensorEventArgs e);
private ContactSensorEventArgs.ReleaseState recentReleaseState;
public void ReportStateChanged()
{
if (statechangedList.Count > 0)
{
var e = new ContactSensorEventArgs()
{
State = recentReleaseState
};
statechangedList.ForEach(t =>
t.Item1.Post(o => t.Item2((ContactSensorEventArgs)o), e));
}
}
List<Tuple<AsyncOperation, OnReleaseStateChanged>> statechangedList = new List<Tuple<AsyncOperation,OnReleaseStateChanged>>();
public event OnReleaseStateChanged ReleaseStateChanged
{
add
{
var op = AsyncOperationManager.CreateOperation(null);
statechangedList.Add(Tuple.Create(op, value));
}
remove
{
var toremove = statechangedList.Where(t => t.Item2 == value).ToArray();
foreach (var t in toremove)
{
t.Item1.OperationCompleted();
statechangedList.Remove(t);
}
}
}
public void Dispose()
{
statechangedList.ForEach(t => t.Item1.OperationCompleted());
statechangedList.Clear();
}
public class ContactSensorEventArgs : EventArgs
{
//......
public ReleaseState State { get; set; }
//......
public enum ReleaseState
{
FullReleased,
PartlyReleased,
NotReleased
}
}
}
I'm using delegates
in my c# windows forms application project.Using that I'm trying to remove items in a list box. I'm getting this null pointer exception and can somebody suggest a way to avoid that?
Delegate
public delegate void OrderEventDelegate (Object sender, OrderEventArgs args);
OrderEventArgs class
public class OrderEventArgs
{
private String message;
public String Message
{
get { return message; }
set { message = value; }
}
private int tableNo;
public int TableNo
{
get { return tableNo; }
set { tableNo = value; }
}
}
Class 1
public partial class Class1 : Form
{
private event OrderEventDelegate readyEvent;
public Class1(HomeForm parent, int tableNo)
{
InitializeComponent();
readyEvent -= new OrderEventDelegate(parent.readyOrder);
}
public void button_click()
{
OrderEventArgs readyOrderArg = new OrderEventArgs();
readyOrderArg.TableNo = 1;
readyOrderArg.Message = "123";
readyEvent(this, readyOrderArg);
}
}
Here readyEvent -= new OrderEventDelegate(parent.readyOrder);readyOrder() is the method which remove items in the list, which is located in the 'Homeform'.
Exception
It is possible to initialize C# events with an empty delegate. This way it can always be called safely without a null pointer check. As shown in this answer: https://stackoverflow.com/a/340618/2404788.
public delegate void OrderEventDelegate (Object sender, OrderEventArgs args) = delegate {};
If there's a possibility of something being null and you can do something about it/don't want to critically fail when it is, then check for it:
if (readyEvent != null) {
readyEvent( ... );
}
But the point here, I suppose, is that you don't want this thing to be null; so you should subscribe a handler to the event. I'm not sure why you're trying to remove a new instance of the delegate handler, but to add one you would use +=.
I'm trying to expose an API such that, I do the following
RegisterCallback<T>(Action<T> func)
{
someObj.FuncPointer = func;
}
Later on, I call func(obj) .. and the obj is of type T that the user said.
More concrete example:
var callbackRegistrar = new CBRegistrar();
callbackRegistrar.RegisterCallback<ISomeClass>(SomeFunc);
public static void SomeFunc(ISomeClass data)
{
//
}
EDIT: So I may not have been clear, so I'll add more code:
I want to make only "one" object of CBRegistrar, and connect it with many Callbacks, as such:
var callbackRegistrar = new CBRegistrar();
callbackRegistrar.RegisterCallback<ISomeClass>(SomeFunc);
callbackRegistrar.RegisterCallback<ISomeOtherClass>(SomeFunc2);
...
In fact the above code is called by reflecting over a directory of plugins.
The user puts this in their code -->
public static void SomeFunc(ISomeClass data)
{
//
}
public static void SumFunc2(ISomeOtherClass data)
{
//
}
It looks to me as if this is not possible using Generics, etc. What it looks like I might have to do is make an interface called IPlugin or something, and ask the user to do this ..
[PluginIdentifier(typeof(ISomeClass))]
public static void SomeFunc(IPluginData data)
{
var castedStuff = data as ISomeClass; // ISomeClass inherits from IPluginData
}
Seems like asking the user to do stuff that we should take care of, but anyway ...
You need a Action<T> func to store it in. There is a semantic check to make here: if someone calls RegisterCallback twice (with different values), do you want to replace the callback, or keep both ? Assuming the latter, someObj probably wants an event (indeed, this entire API could be exposed as an event), so - in the someObj class:
public event Action<T> FuncPointer;
private void InvokeCallback(T data) {
var handler = FuncPointer;
if(handler != null) handler(data);
}
Noting that RegisterCallback could be replaced entirely, still keeping the data on obj:
public event Action<T> Completed {
add { obj.FuncPointer += value; }
remove { obj.FuncPointer -= value; }
}
Then usage would be:
var callbackRegistrar = new CBRegistrar();
callbackRegistrar.Completed += SomeFunc;
Callback functions are not much used in C#. They've been replaced by events which are more elegant and easier to work with.
class CBRegistrar
{
public delegate void ActionRequiredEventHandler(object sender, ISomeClass e);
public event ActionRequiredEventHandler ActionRequired;
void RaiseActionRequiredEvent(ISomeClass parm)
{
if ( ActionRequired != null)
{
ActionRequired(this, parm);
}
}
}
class APIConsumer
{
var callbackRegistrar = new CBRegistrar();
public APIConsumer()
{
callbackRegistrar.ActionRequired += SomeFunc;
}
public void SomeFunc(object sender, ISomeClass data)
{
}
}
If you still want to use Callbacks, you can use Delegates which are more or less function pointer.
The CBRegistrar will need to be generic (if it's OK to keep a single callback type) or it can do some internal casting (if several callback types need to be registered).
public class CBRegistrar<T>
{
private Action<T> callback;
private Dictionary<Type, object> callbackMap;
public CBRegistrar()
{
this.callbackMap = new Dictionary<Type, object>();
}
public void RegisterCallback(Action<T> func)
{
this.callback = func;
}
public void RegisterGenericCallback<U>(Action<U> func)
{
this.callbackMap[typeof(U)] = func;
}
public Action<U> GetCallback<U>()
{
return this.callbackMap[typeof(U)] as Action<U>;
}
}
public interface ISomeClass
{
string GetName();
}
public class SomeClass : ISomeClass
{
public string GetName()
{
return this.GetType().Name;
}
}
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var callbackRegistrar = new CBRegistrar<ISomeClass>();
callbackRegistrar.RegisterCallback(SomeFunc);
callbackRegistrar.RegisterGenericCallback<ISomeClass>(SomeFunc);
var someone = new SomeClass();
callbackRegistrar.GetCallback<ISomeClass>()(someone);
}
public static void SomeFunc(ISomeClass data)
{
// Do something
Console.WriteLine(data.GetName());
}
}
}
In one of my previous questions I explained about a form class that contain form field objects to save data in a user profile object (using profile provider).
The code is here bellow. Basically what I would like to accomplish is to pass as a parameter to my form field objects the field of the Profile object that they should interact in order to save the data later on.
You can see that in the following line:
//LastNameFormLine is an control that was added to my form page.
//The ProfileField parameter stores the field of the UserProfile object that is being manipulated by this control
LastNameFormLine.ProfileField = "UserProfile.LastName";
I was reading about reflection to be able to save this value in the UserProfileVisitor class, but I came across this concept of delegate in C# which I am not sure yet if I fully grasp.
Is it possible to delegate the ProfileField to a property on my UserProfile class? Or should I forget about it and go with reflection?
What would you suggest?
public partial class UserProfileForm : CustomIntranetWebappUserControl
{
protected override void OnInit(EventArgs e)
{
//AutoEventWireup is set to false
Load += Page_Load;
CancelLinkButton.Click += CancelButtonClickEvent;
SaveLinkButton.Click += SaveButtonClickEvent;
base.OnInit(e);
}
private void SaveButtonClickEvent(object sender, EventArgs e)
{
VisitFormFields();
}
private void VisitFormFields()
{
var userProfileVisitor = new UserProfileVisitor();
foreach (var control in Controls)
{
if (control is FormFieldUserControl)
{
var formField = (FormFieldUserControl) control;
formField.Visit(userProfileVisitor);
}
}
userProfileVisitor.Save();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindText();
}
}
private void BindText()
{
LastNameFormLine.LabelText = string.Format("{0}:", HomePage.Localize("Last Name"));
LastNameFormLine.InputValue = UserProfile.LastName;
LastNameFormLine.IsMandatoryField = true;
LastNameFormLine.IsMultilineField = false;
LastNameFormLine.ProfileField = "UserProfile.LastName";
//... the rest of this method is exactly like the 4 lines above.
}
}
public abstract class FormFieldUserControl : CustomIntranetWebappUserControl
{
public string ProfileField { get; set; }
public abstract void Visit(UserProfileVisitor userProfileVisitor);
}
public partial class FormLineTextBox : FormFieldUserControl
{
//... irrelevant code removed...
public override void Visit(UserProfileVisitor userProfileVisitor)
{
if (userProfileVisitor == null)
{
Log.Error("UserProfileVisitor not defined for the field: " + ProfileField);
return;
}
userProfileVisitor.Visit(this);
}
}
public class UserProfileVisitor
{
public void Visit(FormLineTextBox formLine)
{
// The value of formLine.ProfileField is null!!!
Log.Debug(string.Format("Saving form field type {1} with profile field [{0}] and value {2}", formLine.ProfileField, formLine.GetType().Name, formLine.InputValue));
}
// ... removing irrelevant code...
public void Save()
{
Log.Debug("Triggering the save operation...");
}
}
Delegates are not for properties. However, Reflection is slow, may have issues with code security and it's not typesafe and may lead to runtime instead of compile-time problems on naming errors due to the late-bound nature.
That said, you may want to use getter and/or setter methods and use delegates on those.