Before C#6, i was using this routine to deal with generating events in a multi threaded program: (i found it somewhere, but can't remember where):
public static object Raise(this MulticastDelegate multicastDelegate, object sender, EventArgs e)
{
object retVal = null;
MulticastDelegate threadSafeMulticastDelegate = multicastDelegate;
if (threadSafeMulticastDelegate != null)
{
foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
{
var synchronizeInvoke = d.Target as ISynchronizeInvoke;
if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[] { sender, e }));
else
retVal = d.DynamicInvoke(sender, e);
}
}
return retVal;
}
so all i had to do was Eventname.Raise(...,....)
now with C#6, i know the new was it using something like:
Eventname?.Invoke(...);
what i am wondering is, should i change all my event creations to Invoke as it works different to the Raise(), or is it the same thing ?
You should never have been using that method in the first place. It's way too complicated. Instead, something like this would have been better:
public static void Raise(this Delegate handler, object sender, EventArgs e)
{
if (handler != null)
{
handler.DynamicInvoke(sender, e);
}
}
As for whether you should change your event-raising code, I'd say no. Not unless you've got a lot of time to kill and like going through your entire code base replacing perfectly good code.
What you should do is fix your current Raise() method. And feel free for any new code to write it the new C# 6 way, i.e. MyEvent?.DynamicInvoke(this, EventArgs.Empty) (which effectively amounts to the exact same thing as MyEvent.Raise(this, EventArgs.Empty) using the above, except without the extra method call).
Related
Sorry for the title, i didn't find it easy to resume.
My issue is that I need to implement a c# dll that implements a 'scan' method, but this scan, when invoked, must not block the main thread of the application using the dll. Moreover, it is a duty that after the scan resolves it rises an Event.
So my issue (in the deep) is that i'm not so experienced at c#, and after very hard investigation i've come up with some solutions but i'm not very sure if they are the "right" procedures.
In the dll i've come up with:
public class Reader
{
public delegate void ReaderEventHandler(Object sender, AlertEventArgs e);
public void Scan(String ReaderName)
{
AlertEventArgs alertEventArgs = new AlertEventArgs();
alertEventArgs.uuiData = null;
//Code with blocking scan function here
if (ScanFinnished)
{
alertEventArgs.uuiData = "Scan Finnished!";
}
alertEventArgs.cardStateData = readerState[0].eventState;
ReaderEvent(new object(), alertEventArgs);
}
public event ReaderEventHandler ReaderEvent;
}
public class AlertEventArgs : EventArgs
{
#region AlertEventArgs Properties
private string _uui = null;
private uint cardState = 0;
#endregion
#region Get/Set Properties
public string uuiData
{
get { return _uui; }
set { _uui = value; }
}
public uint cardStateData
{
get { return cardState; }
set { cardState = value; }
}
#endregion
}
While in the main app I do:
Reader reader;
Task polling;
String SelectedReader = "Some_Reader";
private void bButton_Click(object sender, EventArgs e)
{
reader = new Reader();
reader.ReaderEvent += new Reader.ReaderEventHandler(reader_EventChanged);
polling = Task.Factory.StartNew(() => reader.Scan(SelectedReader));
}
void reader_EventChanged(object sender, AlertEventArgs e)
{
MessageBox.Show(e.uuiData + " Estado: " + e.cardStateData.ToString("X"));
reader.Dispose();
}
So here, it works fine but i don't know if it's the proper way, in addition i'm not able to handle possible Exceptions generated in the dll.
Also tried to use async/await but found it difficult and as I understand it's just a simpler workaround Tasks.
What are the inconvinients of this solution? how can i capture Exceptions (are they in other threads and that's why i cant try/catch them)? Possible concept faults?
When your class sends events, the sender usually is that class, this. Having new object() as sender makes absolutely no sense. Even null would be better but... just use this.
You shouldn't directly raise events as it might result in race conditions. Might not happen easily in your case but it's just a good guideline to follow. So instead of calling ReaderEvent(new object(), alertEventArgs); call RaiseReaderEvent(alertEventArgs); and create method for it.
For example:
private void RaiseReaderEvent(AlertEventArgs args)
{
var myEvent = ReaderEvent; // This prevents race conditions
if (myEvent != null) // remember to check that someone actually subscribes your event
myEvent(this, args); // Sender should be *this*, not some "new object()".
}
Though I personally like a bit more generic approach:
private void Raise<T>(EventHandler<T> oEvent, T args) where T : EventArgs
{
var eventInstance = oEvent;
if (eventInstance != null)
eventInstance(this, args);
}
Which can then be used to raise all events in same class like this:
Raise(ReaderEvent, alertEventArgs);
Since your scan should be non-blocking, you could use tasks, async/await or threads for example. You have chosen Tasks which is perfectly fine.
In every case you must understand that when you are not blocking your application, your application's main thread continues going like a train. Once you jump out of that train, you can't return. You probably should declare a new event "ErrorEvent" that is raised if your scan-procedure catches an exception. Your main application can then subscribe to that event as well, but you still must realize that those events are not (necessarily) coming from the main thread. When not, you won't be able to interact with your GUI directly (I'm assuming you have one due to button click handler). If you are using WinForms, you'll have to invoke all GUI changes when required.
So your UI-thread safe event handler should be something like this:
void reader_EventChanged(object sender, AlertEventArgs e)
{
if (InvokeRequired) // This true for others than UI Thread.
{
Invoke((MethodInvoker)delegate
{
Text = "My new title!";
});
}
else
Text = "My new title!";
}
In WPF there's Dispather that handles similar invoking.
In the following code, which is better? To call add page from within CardPanelDesigner_AddPage? Or use the Func TransactionFunction??
Basically I want to know if doing the inner func will create a "new function" every time :S I don't even know what I'm asking.
Is there an overhead to doing the inner function or should I use the addpage?
private object AddPage(IDesignerHost Host, object Sender)
{
return null;
}
private void CardPanelDesigner_AddPage(object sender, EventArgs e)
{
IDesignerHost DesignerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
if (DesignerHost != null)
{
Func<IDesignerHost, object, object> TransactionFunction = (Host, Param) =>
{
return null;
};
TransactionInfo("Add Page", DesignerHost, AddPage); //Add page? OR TransactionFunction? :S
}
}
Yes, TransactionFunction will create a new object each time CardPanelDesigner_AddPage is called. The performance overhead of this however will likely be negligible. You should do whatever reads best to you (and your team).
I have the following line in C#:
_timer.ElapsedTick += _somefunction1;
_timer.ElapsedTick += _somefunction2;
_timer.ElapsedTick += _somefunction3;
How to invoke all methods subscribed to _timer.ElapsedTick without specifying the _somefunction ? Somewhere along this pseudo-line
invoke(_timer.ElapsedTick);
You can't invoke an event which is owned by another type. An event can only be invoked from the inside of the class which declares it.
Can it be done using conventional C#? No (as previously stated). But using reflection it is possible. Here is some tested code based on the answer to this MSDN forum thread:
class InvokeFromMe
{
public event EventHandler RaiseMe;
}
class Program
{
static void Main(string[] args)
{
var fromMe = new InvokeFromMe();
fromMe.RaiseMe += fromMe_RaiseMe;
fromMe.RaiseMe += fromMe_RaiseMe1;
fromMe.RaiseMe += fromMe_RaiseMe2;
FireEvent(fromMe, "RaiseMe", null, EventArgs.Empty);
}
static void fromMe_RaiseMe(object sender, EventArgs e)
{
Console.WriteLine("Event Handler 0 Raised");
}
static void fromMe_RaiseMe1(object sender, EventArgs e)
{
Console.WriteLine("Event Handler 1 Raised");
}
static void fromMe_RaiseMe2(object sender, EventArgs e)
{
Console.WriteLine("Event Handler 2 Raised");
}
public static void FireEvent(object onMe, string invokeMe, params object[] eventParams)
{
MulticastDelegate eventDelagate =
(MulticastDelegate)onMe.GetType().GetField(invokeMe,
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, eventParams);
}
}
}
UPDATE
I'm not familiar with the System.Timer.Timer class, so I'm not sure what is different from my provided example. You could perhaps try something like:
public static void FirePublicEvent(object onMe, string invokeMe, params object[] eventParams)
{
MulticastDelegate eventDelagate =
(MulticastDelegate)onMe.GetType().GetField(invokeMe,
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public).GetValue(onMe);
Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, eventParams);
}
}
well i end up here about searching how to simply start event, which is not having any custom args or anything. I know OP question is different! but i had like to share, i hope it helps someone.
Unsimplify version:
var Handler = EventNameHere;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
Simplify version:
EventNameHere?.Invoke(this, EventArgs.Empty);
You could create a function that runs them all:
public void RunAllFuncs()
{
_somefunction1();
_somefunction2();
_somefunction3();
}
This is a work around, you can't loop through the Elapsed event. But to invoke them all, let the timer do the work. This code for System.Timer, not sure which timer you are using.
Presuming the timer is already enabled:
int interval = timer.Interval;
ElapsedEventHandler handler = null;
handler = (s,e) =>
{
timer.Interval = interval; // put interval back to original value
timer.Elapsed -= handler;
};
timer.Elapsed += handler;
timer.Interval = 1; // 1 millisecond, pretty much going to fire right now (as soon as you let it)
Something like that will fire the events, but your original interval will be restarted. You may have to do some math in there if you want to keep the original tick pattern.
I think you probably need to use InvokeMember:
public void GetMethod(string methodName){
var args = new Object[] { [INSERT ARGS IF NECESSARY--SET TO NULL OTHERWISE] };
try
{
var t = new [INSERT NAME OF CLASS THAT CONTAINS YOUR METHOD]();
Type typeInfo = t.GetType();
var result = typeInfo.InvokeMember(methodName, BindingFlags.InvokeMethod, null, t, args);
return result;
}
catch (Exception ex)
{
return ex;
}
}
Then call it like this:
_timer.ElapsedTick += GetMethod("[INSERT METHOD NAME AS STRING]");
Be sure to include this:
using System.Reflection;
Good Luck!
Based on M.Babcock's answer above, with some slight reflection method updates.
Replaced GetField with GetTypeInfo and GetDeclaredField, and dlg.Method with dlg.GetMethodInfo.
using System.Reflection;
...
public static void FireEvent(this object onMe, string invokeMe, params object[] eventParams)
{
TypeInfo typeInfo = onMe.GetType().GetTypeInfo();
FieldInfo fieldInfo = typeInfo.GetDeclaredField(invokeMe);
MulticastDelegate eventDelagate = (MulticastDelegate)fieldInfo.GetValue(onMe);
Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.GetMethodInfo().Invoke(dlg.Target, eventParams);
}
}
With .NET 6 (may work with other versions, too), the following generic method may be helpful. Like in other answers it uses reflection to invoke the EventHandler:
private void InvokeEvent<T, TEvent>(T target, string eventName, TEvent #event)
{
// some reflection magic to fire an event from outside the target class:
if(target == null)
{
throw new ArgumentNullException(nameof(target));
}
Type targetType = target.GetType();
FieldInfo? fi = targetType.GetField(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if(fi != null)
{
EventHandler<TEvent>? eventHandler = fi.GetValue(target) as EventHandler<TEvent>;
if(eventHandler != null)
{
eventHandler.Invoke(this, #event);
}
}
}
It can then be invoked like this:
const string eventName = nameof(Algorithm.Received);
DomainEvent #event = new DomainEvent(payload);
InvokeEvent(targetObject, eventName, #event);
Notes:
The above code also works if multiple methods were added with += to the event handler.
If you want use this code in product you may want to consider more error handling such as parameter checking or throwing an exception if a specific event handler wasn't found.
With each major version of .NET the code using reflection may need to be changed. As .NET 6 is cross-platform running on Windows, Linux, MacOS, etc. I suspect the likelihood of changes breaking the above code is reduced, although not zero.
We are using this code in our automated test suite. In case the code using reflection does in fact change, we only need to change this one method.
Building on the answers before me, the following worked for me:
EventNameHere(null, EventArgs.Empty);
Depending on the signature of the ElapsedTick event, you can fire the event by calling it like a method from inside the class in which it is declared. For example:
ElapsedTick(this, new EventArgs());
You can only call events from inside the class that declares it. If you wrote the timer class, you would invoke it like this:
this.ElapsedTick(this, eventArgs);
Outside the timer class you may do as follows to get similar behavior:
delegate void delegateSample(object sender, EventArgs e);
delegateSample d;
d += new delegateSample(_somefunction1);
d += new delegateSample(_somefunction2);
d(this, EventArgs.Empty);
delegateSample should actually be the type of the ElapsedTick event, instead of declaring another delegate type. I just didn't know the name of that delegate. Just make sure you add each function the ElapsedTick event and the delegate variable you declare then you can call them all from the delegate outside the Timer class.
In a similar question:
What is this pattern called? Soft Lock?
I was asking about the name of the pattern for the code listing below.
public class MyClass
{
public event EventHandler MyEvent;
private bool IsHandlingEvent = false;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
if (IsHandlingEvent) { return; }
IsHandlingEvent = true;
{
// Code goes here that handles the event, possibly invoking 'MyEvent' again.
// IsHandlingEvent flag is used to avoid redundant processing. What is this
// technique, or pattern called.
// ...
}
IsHandlingEvent = false;
}
}
It seems that most of the conversation was centered around why we should an should not do this, so I think that this question provides a better forum to tackle the problem and address all of the issues. What is the better / proper way to handle this?
There are series of problems with that pattern. If you want to invoke the handler only once, you would do something like this:
protected static object _lockObj = new object();
protected static bool _isHandled = false;
void MyClass_MyEvent(object sender, EventArgs e)
{
if(_isHandled)
return;
lock(_lockObj)
{
if(_isHandled)
return;
_isHandled = true;
MyOtherPossiblyRecursiveMethod(); // Actually does all your work
_isHandled = false;
}
}
void MyOtherPossiblyRecursiveMethod()
{
}
This way, only one thread should be able to access the actual work method.
I will use something like:
using( var sl = new SoftLock() )
{
sl.Execute(()=>{....});
}
the execute will raise the internal boolean to prevent re-entering. In the dispose that flag would be resetted. Execute will call the lambda just if the flag is false. This is to ensure flag go to false even if exception happens ( causing handler never executed ) and maybe is a little better to see. Of course this is not thread safe, as the original code, but this because we are talking about preventing double execution from the same thread.
The original code is a sufficient (and very lightweight) way to prevent recursion in a single-threaded app. So if during your event handling function you could get into code that might be firing the event again you will not enter infinite recursion.
But the code is not sufficient to prevent access from multiple threads, due to the potential for race conditions. If you need to ensure only one thread gets to run this event, then you should use a stronger locking mechanism, like a Mutex or Semaphore.
The following works in single- and multi-threaded scenarios and is exception-safe... also if need be it can be modified to allow for a certain level of reentrancy (for example 3 levels)...
public class MyClass
{
public event EventHandler MyEvent;
private int IsHandlingEvent = 0;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
// this allows for nesting if needed by comparing for example < 3 or similar
if (Interlocked.Increment (ref IsHandlingEvent) == 1 )
{
try {
}
finally {};
}
Interlocked.Decrement (ref IsHandlingEvent);
}
}
I would like to remoe duplicate delegates from an event. So I have written the following code. It works fine. My application is a time critcal application. Is there any other optimized mechansim to achieve the same. Please help me
public void FireEvent()
{
Dictionary<Delegate, Delegate> dic = new Dictionary<Delegate, Delegate>();
Delegate[] m = this.Paused.GetInvocationList();
foreach (Delegate d in m)
{
Delegate dout;
if (dic.TryGetValue(d, out dout))
{
continue;
}
else
{
dic.Add(d, d);
}
d.DynamicInvoke(new object[2] { this, null });
}
}
Problem with original approach
If this is really a time critical application, I would strongly advise changing your code.
You construct and populate a new Dictionary<Delegate, Delegate> on every method call. This is quite wasteful.
You use DynamicInvoke, which has slower performance than regular invocation to begin with.
You construct a new object[] to pass as a parameter to your DynamicInvoke call, again on every FireEvent call.
This is a bit of a corruption of the established mechanism for event handling.
Suggestion for improved approach
Here's a much better solution, in my opinion: instead of having this FireEvent method which bends over backwards to ignore duplicate delegates that have been added, why not just prevent delegates from being attached to the event multiple times in the first place?
private HashSet<EventHandler> _pausedHandlers = new HashSet<EventHandler>();
public event EventHandler Paused
{
add // will not add duplicates
{ _pausedHandlers.Add(value); }
remove
{ _pausedHandlers.Remove(value); }
}
Then you can simply raise the event in the much more conventional, time-tested way, confident that no delegates have been attached to the event more than once.
protected void OnPaused()
{
foreach (EventHandler handler in _pausedHandlers)
{
try
{
handler(this, EventArgs.Empty);
}
catch
{
// up to you what to do here
}
}
}
Note on the concept of "duplicate delegates"
The comments to this answer have shed some light on the issue of delegate equality that I felt it would be beneficial to include in this answer. If you're interested, take a look at the following code example I wrote in an attempt to make this topic a little bit easier to understand.
class Program
{
static void Main(string[] args)
{
// Even though the code for FirstHandler and SecondHandler is the same,
// they will not (nor should they) be considered equal for the purpose
// of detecting duplicates.
EventHandler handler1 = FirstHandler;
EventHandler handler2 = SecondHandler;
// Since handler2 and handler3 point to the same method, on the other
// hand, they will (and ought to) be treated as equal.
EventHandler handler3 = SecondHandler;
// So this prints 'False'...
Console.WriteLine(handler1.Equals(handler2));
// ...and this prints 'True'.
Console.WriteLine(handler2.Equals(handler3));
// Now take a look at the code for SetAnonymousHandler below. The
// method accepts an EventHandler by reference and compares it for
// equality to a delegate pointing to an anoymous lambda method. If the
// two are equal, it sets the EventHandler to this new delegate and
// returns true; otherwise it returns false.
// This prints 'True', as handler1 is not equal to the delegate
// declared within the SetAnonymousHandler method.
Console.WriteLine(SetAnonymousHandler(ref handler1));
// HOWEVER, now it prints 'False' for a simple reason: the delegate
// declared in SetAnonymousHandler points to an actual method. The fact
// that it is an anonymous method simply means that the compiler
// automatically generates a "proper" method for it in IL (to see what
// I mean, read the comment at the bottom of this class). So now,
// as with handler2 and handler3 above, handler1 and the delegate
// declared in SetAnonymousHandler point to the same method and are
// therefore equal; the method returns false.
Console.WriteLine(SetAnonymousHandler(ref handler1));
Console.ReadLine();
}
static void FirstHandler(object sender, EventArgs e)
{
Console.WriteLine("Testing");
}
static void SecondHandler(object sender, EventArgs e)
{
Console.WriteLine("Testing");
}
static bool SetAnonymousHandler(ref EventHandler handler)
{
EventHandler anonymous = (sender, e) => Console.WriteLine("Testing");
if (!handler.Equals(anonymous))
{
handler = anonymous;
return true;
}
else
{
return false;
}
}
// Note: When the above method is compiled, the C# compiler generates code
// that would look something like this if translated back from IL to C#
// (not exactly, but the point is just to illustrate that an anoymous
// method, after compilation, is really just like a "proper"
// -- i.e., non-anonymous -- method).
//static bool SetAnonymousHandler(ref EventHandler handler)
//{
// EventHandler anonymous = SetAnonymousHandler_Anonymous;
// if (handler.Equals(anonymous))
// {
// handler = anonymous;
// return true;
// }
// else
// {
// return false;
// }
//}
//static void SetAnonymousHandler_Anonymous(object sender, EventArgs e)
//{
// Console.WriteLine("Testing");
//}
}