When to define an event, and when a delegate
Here is the basic idea:
- If something has happened inside your class, like a property changed, and you want to inform the possible subscribers about it, then you need to define an event in your class, and raise the event when something happens (like property changed).
- If you want to inject a piece of functionality in a method, or a property, then your method or your property need to accept a delegate as parameter, one example is the link extension methods.
Events are declared as class members, and you add a delegate to them using += operator.
Delegates are type and will be declared usually as namespace members (like classes).
After you defined a delegate (which is like defining signature of a method as a type with a name), then you can define fields, properties variables, input or output arguments of that delegate type.
In the following examples you will see the usage, and see some differences.
Delegate Example
After you defined a delegate (which is like defining signature of a method as a type with a name), then you can define fields, properties variables, input or output arguments of that delegate type, for example, let's say you have defined:
public delegate bool Criteria(string x);
Then you can define the following in your class:
public IEnumerable<string> Where(IEnumerable<string> input, Criteria criteria)
{
foreach (var item in input)
if (criteria(item))
yield return item;
}
Which is a good example of injecting a functionality, in a method.
Event Example
Assuming you have defined the following delegate (which is going to be used to define an event):
public delegate void NameChangedEventHandler(string name);
It basically is defining a type which explains a method, accepting a string parameter, and a void return value; and since I'm going to use it for an event, by assigning a name NameChangedEventHandler
, I'm saying a method which is going to handle the NameChanged
event, should follow that signature.
Then you can define the event and the property and raise the event like this:
public event NameChangedEventHandler NameChanged;
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
NameChanged?.Invoke(value);
}
}
What is Action, or Action<T>, or Funct<T>?
These are just some predefined delegates. Everytime that you want to pass a delegate as a method parameter, then you need to define the delegate. These actions and funcs makes it easier for you. For example in above delegate example, instead of defining a new delegate type, I could easily use Fucn<string, bool>
which basically means a method accepting a string parameter which return bool.
Looking at the source code of .NET framework, you see:
namespace System
{
public delegate void Action<in T>(T obj);
public delegate void Action();
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T, out TResult>(T arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate void Action<in T1, in T2, in T3, in T4, in T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
public delegate int Comparison<in T>(T x, T y);
public delegate TOutput Converter<in TInput, out TOutput>(TInput input);
public delegate bool Predicate<in T>(T obj);
}
What's the difference between a delegate field and an event?
Lets say you have defined both of following in your class:
- public event EventHandler MyEvent;
- public EventHandler MyDelegateField;
They are very similar (as they both rely on EventHandler
which is a predefined delegate), but they are different as well:
- The first one is an event, the second one is a public field of delegate type.
- No one can assign a delegate to your event, they only can add (+=) or remove delegates (-=), but in addition to add (+=), and remove (-=), they can assign (=) delegate to the public field.
- No one can raise event like a delegate outside of your class, but they can invoke your public delegate field.
- Like properties and methods, you can define events in interfaces but you cannot do the same for fields.
Here are a few examples to demonstrate the differences which I mentioned above:
-
class1.MyEvent = Something;
doesn't work. -
class1.MyDelegateField = Something
works and will assign a new multicast delegate to the field. -
class1.MyEvent();
doesn't work outside of your class. -
class1.MyDelegateField();
works and will run all the delegates which has been assigned to the field. -
interface ISomething { event EventHandler MyEvent;}
is a valid declaration. -
interface ISomething { EventHandler MyDelegateField}
is invalid.
More information
You can learn more about the events: