Delegation and events are relatively old techniques in C#, starting with theC#1.0
The core role is to pass and use methods as parameters (variables). One of the delegate is the foundation, need to master, programming commonly used in the Lambda expression, Action, Func are delegates, including events are also based on the realization of the delegate.
01, recognize delegate delegate
1.1 What is a commission?
Delegate is a special type used to wrap methods to be passed and called as objects, similar to function pointers.delegate The keyword is used to define a delegate type, the syntax is similar to the method declaration, can be regarded as a "method signature template", and the same as the method defines the return value of the method, parameters.
- expense or outlay
delegate
The defined delegate isa classThe "method name" is the name of the delegate type. - Delegates are used in the same way as other common types, with the instance pointing to a reference to a method whose declaration matches the "method signature template" of the delegate definition (Support for covariant inverters)。
- Delegates support linking multiple delegates (methods), called multicast delegates (MulticastDelegate), which are called when executed.
public delegate void Foo(string name); //assert a delegate type
void Main()
{
Foo faction; //Declare a Foo delegate (instance) variable.
faction = DoFoo; //Assign a method
faction += str => { ($"gun {str}"); }; // Add multiple "method instances".
faction += DoFoo; // continue adding, repeatable
faction("sam"); //Execute the delegate, multiple methods will be executed sequentially.
("zhang"); // Same as above, the above call is still an Invoke method.
}
private void DoFoo(string name){
($"hello {name}"); }
}
The main usage scenario of delegate: the core is to pass the method as a parameter, separating the method declaration and method implementation.
- callback method, wrapping methods as delegates and passing them as arguments decouples method assertion, implementation, and invocation, which can be done in different places.
- Lambda expressionThis is a simplified syntactic form of delegation, which is more concise and more commonly used.
- event, events are a special kind of delegates, which are implemented based on delegates and can be seen as an encapsulation of delegates.
1.2、Delegate API
🔸Delegate properties | clarification |
---|---|
Method | Gets information about the method represented by the delegate, returning the last of multiple values. |
Target | Get the object instance to which the delegate method belongs, multiple values return the last one, and for static methods thenull 。So be careful.: Delegates and events should be removed when they are not used to avoid GC failing to release resources. |
🔸Delegate static member | - |
CreateDelegate | Create a delegate of the specified type in code, including multiple overloaded methods |
Combine(Delegate, Delegate) | Combine multiple delegates into a new delegate (chain) to simplify syntax+ 、+= :Foo d = d1 + d2;
|
Remove(source, value) | Removes the call list of the specified delegate and returns the new delegate. Simplified syntax- 、-= :d -= d1
|
RemoveAll(source, value) | As above, the difference isRemove value removes the last one found.RemoveAll Remove all found |
🔸MulticastDelegate Member | - |
GetInvocationList() | Returns a list of the delegates of this multicast delegate in order of invocation |
1.3 Decryption delegate "type"
expense or outlaydelegate
defined delegate, the compiler will automatically generate a sealed class, SO, the delegate is essentially a class. The delegate class inherits from,MulticastDelegate
having also inherited fromDelegate is the base class for delegates, and they are both abstract classes.
delegate
The compiled IL code of the defined delegate is as follows (simplified) and can be viewedOnline sharplab。
public delegate void Foo(string name,int age); //Declaring a delegate type
//Compiler-generatedFoocommissioning class(Simplified Code)
class public auto ansi sealed Foo extends []]
{
void Foo(object obj, IntPtr method) { ... }
public virtual void Invoke (string name,int32 age) { ... }
public virtual BeginInvoke (string name,int32 age, callback, object 'object') { ... }
public virtual void EndInvoke (class [] result) { ... }
}
- The constructor of the delegate has two parameters, the
obj
is the object on which the method resides.method
is a method pointer. This constructor is called by the compiler, just understand it. - Three ways to execute a delegate
Invoke
、BeginInvoke
cap (a poem)EndInvoke
Signature and proxy affirmation are consistent. - To execute a delegate (method) is to call the
()
The simplified syntax isfoo()
。BeginInvoke
cap (a poem)EndInvoke
for asynchronous calls. - Because a delegate is essentially a class, the definition of a delegate is usually external to the class (on a level with the class).
📢 Delegation, event execution, recommended use
?.Invoke
to determine if thenull
:foo?.Invoke()
Test the inheritance hierarchy of a delegate:
public delegate void Foo(string name); //Declaring a delegate type
void Main()
{
Foo faction; //Affirming aFoodelegate variable
faction = DoFoo; //assign a value to something
var ftype = ();
while (ftype != null)
{
();
ftype = ;
}
//exports:
//Foo
//
//
//
}
private void DoFoo(string name){
($"hello {name}");
}
1.4、MulticastDelegate
The delegates and events we use in our coding are really allMulticastDelegate, which can contain multiple (single) commissions.MulticastDelegate
There is a chain of delegates in the_invocationList
, which can hold multiple (single) delegates (which can be added repeatedly). When a delegate is executed, the delegate methods in the delegate chain table are executed sequentially.
🔸 Add Remove: Recommended+
、-
operator adds and removes delegates, which is essentially a call to theDelegate
static method、
。
📢take note of: Delegate the method of
+
、-
is thread-unsafe, the eventadd
、remove
is thread-safe.
🔸 Enforcement Mandate ()/A()
,: all (delegated) methods are executed. This can be accomplished with theGetInvocationList() Get a list of delegates (methods) to manually control execution.
- If the execution of one of the methods reports an error, the later ones in the chain table will not be executed.
- If the delegate method has a return value, you can only get the last result.
📢take note of: The add and remove operations return a new delegate, and the original delegate is not affected.The commission is constant!
public delegate void Foo(string name); //assert a delegate type
void Main()
void Main()
Foo f1 = default; // Declare a Foo delegate variable.
f1 += DoFoo; //add a method
f1 += DoFoo; //add another method
f1 += str => { ($"gun {str}"); }; //continue adding
f1("sam"); //execute the method 3 times
f1 -= DoFoo; //removed
f1("sam"); //executed method 2 times
Foo f2 = DoFoo; //Remove
Foo f3 = f1+f2; //combined delegate
Foo f4 = (Foo)(f1,f2); //same as above
(f3==f4); //True, same delegate if the elements in the internal method list are the same
(f3-f2 == f1); //True, remove delegation
}
private void DoFoo(string name)
{
($"hello {name}"); }
}
1.5. Anonymous Methods and Lambda Expressions
-
anonymous methodis a method that has no name (name), using the
delegate
Keyword assertion that can be passed to a delegate or Lambda expression. - Lambda expressionLike anonymous methods, they are essentially delegates, and the generated IL code is similar.Lambda expressions are more concise and support type inference, so they are basically used in modern programming.
public delegate void Foo(string name); //Declaring a delegate type
void Main()
{
//anonymous method
Foo f1 = delegate(string name){
(name);
};
Action a1 = delegate() { ("hello");};
f1("sam");
a1();
//Lambdadisplayed formula
Foo f2 = name=>(name);
f2("king");
}
Anonymous methods, Lambda methods Will be compiled as a private method in a private class.
02、Built-in delegate type Action, Func
From the above it can be seen that the delegate will create a type at compile time, in order to improve performance, efficiency and avoid a large number of unnecessary repetitive delegate definitions, the.Net
There are some built-in generic delegatesAction、Func, which basically satisfies most common scenarios.
- Action: Delegates supporting 0 to 16 generic parameters with no return value.
- Func: Supports 0 to 16 input generic parameters, and one generic delegate with a return value.
-
Predicate:
bool Predicate<in T>(T obj)
The delegate used to test the judgment returns the result of the test.bool
。
Source Code:
public delegate void Action();
public delegate void Action<in T>(T obj);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
...
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 bool Predicate<in T>(T obj);
upstream delegate parameterin
、out
are modifiers that mark mutability (covariance, inversion), as detailed later inGeneralized T & Covariant Inversion》
03、Awareness EventEvent
3.1 What is an eventevent
?
eventis a special type of delegate, he is based on the delegate implementation, is a further encapsulation of the delegate, so the use is similar to the delegate. Events useevent
keyword is asserted, any other component can subscribe to the event, and when the event is triggered, it calls all the delegates (methods) that have subscribed to it.
Events are a delegate-based (event-driven) programming model for implementing a publish-subscribe based notification mechanism between objects is one way to implement the observer pattern. Commonly used in GUI programming, asynchronous programming, and other systems that require message-based systems.
void Main()
{
var u = new User();
//Subscribe to events
+= (sender, e) => { (sender); };
(100);
(200);
}
public class User
{
public int Score { get; private set; }
public event EventHandler ScoreChanged; //Defining Events,Using the built-in“event”commission EventHandler
public void AddScore(int score)
{
+= score;
?.Invoke(this, null); //触发event
}
}
🔸 Key players in the event:
-
① Publisher of the event, the owner of the published event, triggers the event at the right time, and passes information through the event parameters:
-
sender
: The event source, the publisher who triggered the event. -
EventArgs
: event parameters, generally inherited fromobject, which of course is not required in the
.NET Core
The event parameter in can be of any type.It's just an empty
class
Nothing.
-
-
② Subscribers to the event: Subscription to a published event, with specific actions performed after the event occurs.
📢 EventHandler(object? sender, EventArgs e)、EventArgs
<T>
、Sort of Microsoft's standard event pattern, a customary convention.
🔸 Event Usage Practices:
- utilization
+=
Subscribe to events, with support for any number of subscriptions.-=
Remove unused event subscriptions to avoid memory overflow, note that the-=
Doesn't work for anonymous methods, Lambda, because it's a new delegate each time. - Events are triggered with judgment
null
to avoid triggering an error when there is no subscription:Progress?.Invoke()
。 - Event delegate types end in "EventHandler" and are used in most scenarios.
EventHandler<TEventArgs>
Simply, of course, customize it, or useAction
。
🔸 event naming: noun + verb (passive)
- The incident has occurred withpast tense:Closed、PropertyChanged。
- The event is about to occur using thepresent tense,Closing、ToolTipOpening。
- Subscribed methods are usually prefixed with "
On
”、“Raise
”,+= OnProgress;
3.2. Decryption events - "encapsulated delegates"
Event Definition:public event EventHandler MyEvent;
whichEventHandler
is a delegate, the source code of which is below:
public delegate void EventHandler(object? sender, EventArgs e);
public delegate void EventHandler<TEventArgs>(object? sender, TEventArgs e);
When an event is defined, the C# compiler generates an event wrapper around the delegate, similar to the way properties are wrapped around fields, online.sharplabSource Code.
//Define an event
public event EventHandler MyEvent;
//define an event with other delegates
public event Action<string> MyEvent2.
//compiled IL code (simplified) **********
// Delegate fields
private EventHandler m_MyEvent;
// Similar to get and set accessors for properties, subscribe and unsubscribe to events via + -.
public event EventHandler MyEvent
{
add { m_MyEvent += value; } //
remove { m_MyEvent -= value; } //
}
- The "EventHandler" that defines the event is a delegate, it can be any delegate type, most of the built-in generic delegates are used in C#.
EventHandler<TEventArgs>
。 - The compilation generates a private delegate field
m_MyEvent
, which is the heart of the matter. - generated
add
Subscribe,remove
The unsubscribe method, which controls the addition and removal of delegates, is used with the+=
、-=
Syntax. The above code is simplified, the actual code to be a little more complex, mainly to add a thread-safe processing. - Custom events can also be created directly using the above example's
add
、remove
The way it is encapsulated.
📢 From the above you can see that events are encapsulated based on delegates, similar to properties encapsulating fields. The external can only
add
Subscribe,remove
Unsubscribe and the execution (triggering) of events (delegates) can only be done internally.
3.3. Standard event model
There are a large number of event applications within C# that form a default event (standard) schema that mainly defines the delegates used to create events, event parameters.
- : event parameter, which is the core of the standard event model and serves as a base class for event parameters to inherit from custom implementations of some of the fields (attributes) to be passed by the event.
- The delegate return value is
void
。 - Delegate two parameters
sender
、EventArgs
,sender
is the object that triggers the event and is also the broadcaster of the event;EventArgs
is the event's parameter. - The delegate ends with the name "EventHandler".
- Built-in generalized versions
EventHandler<TEventArgs>
can fulfill the above conditions and is a more general standard event delegate.
public class EventArgs
{
public static readonly EventArgs Empty = new EventArgs();
}
public delegate void EventHandler(object? sender, EventArgs e);
//Generic generic version
public delegate void EventHandler<TEventArgs>(object? sender, TEventArgs e);
Of course this this pattern is not required, just a programming habit or norm.
3.4. Should I use delegates or events?
Event is based on delegate, the function of the event delegate mostly can support, both function and use are relatively similar, both support unicast, multicast, late binding, then how to choose between the two?
- Events generally have no return value, but of course you can if you want to.
- Events provide better encapsulation, similar to the encapsulation of fields by properties, in line with the principle of opening and closing. Events can only be executed internally, externally only
+=
Subscribe,-=
Unsubscribe.
✅So the conclusion:
- Simple scenarios with delegates: one-to-one communication, passing methods.
- Complex scenarios with events: one-to-many communication, need for security permission encapsulation.
04. other - delegated performance issues?
From the previous section we know that all delegates are actually a multicast delegate type, and that the execution of a delegate is actually the execution of theInvoke()
method, which internally iterates through the list of methods to execute, which is quite a bit slower than a direct method call.
public static int Sum(int x, int y) => x + y; //methodologies
public static Func<int, int, int> SumFunc = Sum;//commission
public void Sum_MethodCall() //直接调用methodologies
{
int sum = 0;
for (int i = 0; i < 10; i++)
{
sum += Sum(i, i + 1);
}
}
public void Sum_FuncCall() //调用commission
{
int sum = 0;
for (int i = 0; i < 10; i++)
{
sum += SumFunc(i, i + 1);
}
}
exist.Net6
run inBenchmark
The test comparison is as follows, the direct call is 4-5 times more efficient.
exist.Net7
、.Net8
A number of performance optimizations have been made to achieve similar performance for delegate calls as for direct calls, so you no longer have to worry about performance flaws with delegates. The following figure shows the performance of the.Net8
centerBenchmark
Testing.
bibliography
- and the delegate keyword
- Standard .NET Event Patterns
- Still can't figure out [commissions and events]?, suitable for starters.
- Understanding events in C# from the ground upIt's a little more detailed and good for getting started.
- What's the deal with delegates and events in C#?B Station Video
- The evolution of delegate performance in .NET