When subscribing to events in .NET do I need to create a new instance of the delegate such as
toolbarControl1.OnUploadEventHandler +=
new ToolbarControl.UploadEventHandler(toolbarControl1_OnUpload);
Or is it better to do the following?
toolbarControl1.OnUploadEventHandler += toolbarControl1_OnUpload;
Thanks in advance.
The second one takes less coding and both mean the same.
You might want to consider using generic version of EventHandler - EventHandler<TEventArgs>. You will save on declaring all those delegates.
You can also use lambda expressions, ie.
toolbarControl1.OnUploadEventHandler +=
(sender, args) => { /* Your code goes here */ };
You can do both, so its your preference.
You can also do things like this for very simple handlers to save writing a delegate function:
toolbarControl1.OnUploadEventHandler += (s, e) => uploadCount +=1;
The code speaks for itself:
using System;
class Program
{
void SomeMethod(object sender, EventArgs e) { }
event EventHandler SomeEvent;
static void Main(string[] args)
{
var prog = new Program();
// Demonstrate that they are equivalent
prog.SomeEvent += new EventHandler(prog.SomeMethod);
prog.SomeEvent -= prog.SomeMethod; // Sugar for new EventHandler(prog.SomeMethod)
Console.WriteLine("Number of SomeEvent subscribers is {0}", (prog.SomeEvent != null ? prog.SomeEvent.GetInvocationList() : new Delegate[0]).Length);
// Why are they equivalent?
var d1 = new EventHandler(prog.SomeMethod);
var d2 = new EventHandler(prog.SomeMethod);
Console.WriteLine("Delegates are reference equal {0}", Object.ReferenceEquals(d1, d2));
Console.WriteLine("Delegates are equivalent {0}", d1 == d2);
}
}
They are equivalent. The second one only provides better readability.
They are equivalent unless you need to keep a reference to the delegate so as to unsubscribe.
Related
I have a quick question about coding delegates.
Why do you have to
pf = t.Print; //instantiate and initialize the delegate.
code
delegate void PrintFunction();
public class Test
{
public void Print()
{
Console.WriteLine("Print 1 --instance");
}
public static void Print1()
{
Console.WriteLine("Print 2 -- static");
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
PrintFunction pf;
pf = t.Print; //instantiate and intialize the delegate
pf += Test.Print1;
pf += t.Print;
if (null != pf)
{
pf();
}
else
Console.WriteLine("delegate is empty");
}
}
}
Delegates are immutable reference types, their default value is null. The default constructor for the delegate accepts a method that matches its signature.
So you can do this:
var pf = new PrintFunction(Test.Print1);
pf += t.Print;
Or:
var pf = Test.Print1;
pf += t.Print;
Or:
var pf = null;
pf += Test.Print1;
pf += t.Print;
Edit:
Source that Delegates are reference types: MSDN
A reference type contains a pointer to another memory location that
holds the data. Reference types include the following:
String.
All arrays, even if their elements are value types
Class types, such as Form
Delegates
You do not have to call the code pf = t.Print;. It is perfectly acceptable to write pf = null;.
If you remove the line pf = t.Print; you'll just discover that the compiler is giving you the error "CS0165 Use of unassigned local variable 'pf'".
This is no different than if you wrote the code:
bool flag;
if (flag)
{
}
It's nothing to do with it being a delegate. It's just a compiler error.
so you have to initialize the delegate the first before you call it, like when calling a class. Also the delegate signature has to match the method that is calling the delegate.
Thanks everyone for the help.
Should of coped it before i posted the question.
Thanks again.
By default delegate value is null you should initialize it to something and then use it or add other methods. In your sample there will be 2 times called t.Print and one time Test.Print1.
Good practice is to initialuize delegate to nullable object and then use it without any null checking like below.
PrintFunction pf = () => {};
pf += Print1;
pf += Print;
pf += Print1;
pf();
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.
Sorry to ask all, but I'm an old hand Vb.net guy who's transferring to c#. I have the following piece of code that seems to activate when the (in this case) postAsync method is fired. I just don;t understand what the code is doing (as follows):-
app.PostCompleted +=
(o, args) =>
{
if (args.Error == null)
{
MessageBox.Show("Picture posted to wall successfully.");
}
else
{
MessageBox.Show(args.Error.Message);
}
};
if anyone could explain what the += (o,args) => is actually acheiving I'd be so greatful....
many thanks in advance.
Tim
(o,args) => defines a lambda expression that takes two parameters named o and args. The types of those parameters is inferred according to the type of PostCompleted (if PostCompleted is an EventHandler, then they will be respectively of type Object and EventArgs). The expression's body then follows after the =>.
The result is than added as an handler to PostCompleted.
As such, it's a less verbose way to write:
app.PostCompleted += delegate(object o, EventArgs args)
{
// ...
};
Which is a shorthand for:
void YourHandler(object o, EventArgs args)
{
// ...
}
// ...
app.PostCompleted += YourHandler;
That is an added handler for the PostCompleted event using a lambda expression. It is similar to
app.PostCompleted += MyHandler;
// ...
private void MyHandler(object sender, EventArgs e) {
// ...
}
But when using lambda expressions, you can't detach the handler easily.
It's shorthand for a delegate defining the event handler for the POST completion event:
app.PostCompleted += delegate(object o, EventArgs args) {
// ...
};
See also Anonymous Methods.
Assuming PostCompleted is an event, you are basically creating an event handler using lambda notation.
This code snipped is equivalent to:
app.PostCompleted += delegate (o, args)
{
if (args.Error == null)
{
MessageBox.Show("Picture posted to wall successfully.");
}
else
{
MessageBox.Show(args.Error.Message);
}
};
The vb.net equivalent would look like this:
AddHandler app.PostCompleted, Function(o, args)
''# ...
End Function
Note that this requires Visual Studio 2010/.Net 4, but the C# code works back in Visual Studio 2008/.Net 3.5.
But that's only partly true. In C#, this is a way to define a method as an event handler in one place. In VB.Net, you can use the Handles keyword, and so the actual equivalent might look more like this:
Public Sub App_PostCompleted(ByVal Sender as Object, ByVall e As EventArgs) Handles app.PostCompleted
''#
End Sub
But even that's not completely equivalent, since you gave the method a name and can call it from anywhere. The only reference to the C# code (and thus the only way to call it) is through the event subscription.
The (o,args) => part is a lambda expression, which is an anonymous function.
the += part assigns the lambda expression to be called when the event fires.
This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...
This question already has answers here:
Unsubscribe anonymous method in C#
(14 answers)
Closed 8 years ago.
Say if I listen for an event:
Subject.NewEvent += delegate(object sender, NewEventArgs e)
{
//some code
});
Now how do I un-register this event? Or just allow the memory to leak?
Give your instance of the anonymous delegate a name:
EventHandler<NewEventArg> handler = delegate(object sender, NewEventArgs e)
{
//some code
};
Subject.NewEvent += handler;
Subject.NewEvent -= handler;
If you need to unregister an event, I recommend avoiding anonymous delegates for the event handler.
This is one case where assigning this to a local method is better - you can unsubscribe from the event cleanly.
To remove the handler on first invocation:
//SubjectType Subject = ..... already defined if using (2)
EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
// (1)
(sender as SubjectType).NewEvent -= handler;
// or
// (2) Subject.NewEvent -= handler;
// do stuff here
};
Subject.NewEvent += handler;
You can create method for unregistering from all listeners of event. This not exactly what you whant, but sometimes it can be helpfull. For example (this really works =)) :
class Program {
static void Main(string[] args) {
A someClass = new A();
someClass.SomeEvent += delegate(object sender, EventArgs e) {
throw new NotImplementedException();
};
someClass.ClearEventHandlers();
someClass.FireEvent();
Console.WriteLine("No error.");
}
public class A {
public event EventHandler SomeEvent;
public void ClearEventHandlers() {
Delegate[] delegates = SomeEvent.GetInvocationList();
foreach (Delegate delegate in delegates) {
SomeEvent -= (EventHandler) delegate;
}
}
public void FireEvent() {
if (SomeEvent != null) {
SomeEvent(null, null);
}
}
}
}
You need a name for your anonymous function, and then, you can only do it as long as the name is in scope:
var handler = new EventHandler(delegate(object o, EventArgs e)
{
//do something...
};
Subject.NewEvent += handler;
// later on while handler is still in scope...
Subject.NewEvent -= handler;
Do you need to un-register it for a reason other than leakage?
Regarding the "Or just allow the memory to leak" bit, when Subject is cleaned up by the Garbage Collector, your anonymous delegate should be cleaned up as well, so there shouldn't be a leak.
There is another question (of mine) which goes into this in some (too much) detail: Weak event handler model for use with lambdas.
However, now that the Reactive Framework has come out, I'd seriously consider looking into that in this kind of situation.