This brief introduction of the use of the delegate. Many of the articles commissioned will say: The concept of the Commission and the event is like a hurdle, passed the threshold of the people, think it is too easy, and no past people every time to see the delegates and events feel panic. It is true that this thing, like the first pointer to the C language, is a very tangled sensation, and it is always felt to call a method directly, and why not to define a delegate. In fact, in C # Many of the technology is to reuse and simplify the code, the delegate is no exception, many use C # polymorphism to achieve the design pattern can be used to rewrite the way, can be understood as a lightweight design model bar. The blogger intends to draw a special share of the following polymorphism and delegate implementation of design patterns and similarities and differences. This article first introduces the use of simple delegates.
What is a delegate: a Delegate in C # (Delegate) is similar to a pointer to a function in C or C + +. In the words of bloggers, a delegate is a reference type that allows the method name to be passed as a parameter. It defines the type of the method, which is the abstraction of the method, and conversely, the method can be interpreted as an instance of the delegate, such as public delegate void Testdelegate (String str), which defines all parameter types as String, An abstraction of a method that does not return a value.
Second, what to use the delegate: Remember the blogger just started to do the project when he saw commissioned the writing on the head big, always feel that there is nothing to look for, the only advantage seems to be that the code looks cool ~ ~ With the accumulation of work, it is found that some small requirements of the project to use this lightweight delegate to achieve when it can really reduce the amount of code.
third, the use of the Commission:
1. The delegate type within the. Net Framework: A friend who has used a delegate may have noticed that there are two types of delegate variables defined in C # that basically meet our general needs.
(1) Delegate of action type: C # defines the action delegate for abstracting a method that has no return value. To go to the definition of the action variable is the simplest form of it:
Summary:
Encapsulates a method that does not have parameters and does not return a value.
[Typeforwardedfrom ("System.core, version=3.5.0.0, Culture=neutral, publickeytoken=b77a5c561934e089")]
public delegate void Action ();
It is defined as a delegate that has no parameters to return a value. The action also provides 16 generic delegates that define incoming parameters for the method:
Let's look at how they use it, we first define the test methods:
private static void Test5 (int a, int b, int c)
{
//...
}
No parameter no return value
private static void Test1 ()
{
Console.WriteLine ("Func Test1, no Parameter");
}
There are parameters without return value
private static void Test2 (String str)
{
Console.WriteLine ("Func Test2, Parameter is" + str);
}
//No parameters have return value
private static Object Test3 ()
{
Console.WriteLine ("Func Test3, Parameter");
Return Guid.NewGuid (). ToString ();
}
Parameter has return value
private static Object Test4 (String strres)
{
Console.WriteLine ("Func Test4, Parameter and Re Turn Value ");
return strres;
}
Call:
static void Main (string[] args)
{
//1. No parameter no return value method
var oAction1 = new Action (Test1);
Oaction1.invoke ();//Call Way one
oAction1 ();//Call Mode two
//2. There is no return value
var oAction2 = new Action<int, int, int > (TEST5);
Oaction2.invoke (1, 2, 3);
OAction2 (1, 2, 3);
anonymous method invocation
var oAction3 = new Action<int, int, int> ((a,b,c) => {
//...
});
Oaction3.invoke (1, 2, 3);
}
(2) Func type of delegate: Remember the parameters of methods such as the extension method where (), Select () in LINQ. public static ienumerable<tsource> where<tsource> (this ienumerable<tsource> source, func< TSource, bool> predicate). The argument here is a Func type of delegate. C # inside Func type delegates are used to handle methods with parameters that have return values. Not much to say, on the code:
static void Main (string[] args)
{
var oFunc1 = new func<object> (TEST3);
var ofuncRes1 = Ofunc1.invoke ();
var oFunc2 = new func<string, object> (TEST4);
OFUNC2 ("a");
}
Know the Func method can be pushed to think of our magic Lamada expression, in fact, Lamada expression is an anonymous delegate.
var lsttest = new list<string> ();
var lstres = lsttest.where (x => x.contains ("_"));
The Lamada expression in this where we disassemble him:
private static bool Testwhere (string x)
{
Return X.contains ("_");
}
var ofunc = new func<string, bool> (Testwhere);
Lstres = Lsttest.where (Ofunc);
is not the same as ~ ~
2, Custom delegate:
public delegate void Testdelegate (String str);
In fact, many people should have written their own action, Func type of delegate. It is also simple to define a generic delegate yourself:
public delegate void Myaction<in t> ();
Public delegate TResult Myfunc<in T, out tresult> (t arg);
In fact, the use of the system and the action and Func basically no difference.
3. The merger and dismantling of the delegates are shared in the event. This article and the ...
4, if according to the above method to use the delegate, it really is to be awkward dead, because the call method directly with the method name call is good, why also want to define a delegate variable to call, this is not to complicate the simple problem. Indeed, the above is just for the purpose of introducing the code written by the delegate, the actual project will not be so used. In fact, a delegate is typically used in a project to pass a delegate variable as a parameter or a function callback. Look at the following code:
Class program { static void main (String[] args) { person
strhelper = new person (); string r1 = strhelper.processfunc ("Chinese, ")
Hello ", new mydelegate (Strhelper.chinesesayhello)); string r2 = strhelper.processfunc ("中文版",
"Hello", new mydelegate (Strhelper.englishsayhello); string r3 = strhelper.processfunc ("Japanese",
"こんにちは", new mydelegate (Strhelper.japanesesayhello));
console.writeline (R1);
console.writeline (R2); console.writeline (R3);
console.readkey (); &NBSP;&NBSP;&NBSP;&NBSP} public delegate string mydelegate (string s1, string s2
); Public class person { public string processfunc (STRING&NBSP;S1, string s2, mydelegate process) {
return process (S1,&NBSP;S2); &NBSP;&NBSP;&NBSP;&NBSP} public string chinesesayhello (string s1, STRING&NBSP;S2) { return s1 + "
, "+ s2; &NBSP;&NBSP;&NBSP;&NBSP} public string englishsayhello (string s1, STRING&NBSP;S2) { return s1 +
"," + s2; } public sTring japanesesayhello (STRING&NBSP;S1,&NBSP;STRING&NBSP;S2) {
return s1 + "," + s2; &NBSP;&NBSP;&NBSP;&NBSP}}
Get the result:
The public string Processfunc (string s1, string s2, mydelegate process) defines a callback function that can pass any one of the methods conforming to the delegate to the desired result. To look closely at this design is very similar to the factory design pattern, I simply constructed a factory:
Public class person { public virtual string sayhello (string &NBSP;S2) { return s2; &NBSP;&NBSP}} public class chinese : person { public override string sayhello (STRING&NBSP;S2) {
return "Chinese," + s2; &NBSP;&NBSP;&NBSP;&NBSP}} public class english : person { public override string sayhello (STRING&NBSP;S2) {
return "中文版," + s2; &NBSP;&NBSP;&NBSP;&NBSP}} public class japanese : person { public override string sayhello (STRING&NBSP;S2) { return "Japanese," + s2; &NBSP;&NBSP;&NBSP;&NBSP}}//main function calls Class program { static void main ( String[] args) { var r1 = getperson ("Hello").
SayHello ("Hello"); var r2 = getperson ("Hello").
SayHello ("Hello"); var r3 = getperson ("こんにちは").
SayHello ("こんにちは");
console.writeline (R1);
console.writeline (R2);
console.writeline (R3);
console.readkey (); &NBSP;&NBSP;&NBSP;&NBSP} public static person getperson (string Strtype) { if (strtype == "Hello")
Return new chinese (); else if (strtype == "Hello")
return new english (); else
return new japanese (); &NBSP;&NBSP;&NBSP;&NBSP} }
The results are the same as above:
Design Pattern Instances
This paper simply extracts several design patterns to be implemented according to polymorphism and delegate, of course, the focus here is not on design patterns, but in order to make readers better understand delegates. So many details of the design pattern may be skipped in this article.
A simple factory model: This article on the use of calculator examples to explain.
1, polymorphic implementation of simple factory model.
class program2 { static void main (String[] args) {&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;//1. Using polymorphism to implement simple Factory mode
int x = 8, y = 2; var ires1 = getobject ("+").
Compute (X, y); var ires2 = getobject ("-").
Compute (X, y); var ires3 = getobject ("*").
Compute (X, y); var ires4 = getobject ("/").
Compute (X, y);
console.writeline (IRES1);
console.writeline (IRes2);
console.writeline (IRES3); console.wrIteline (IRES4);
console.readkey (); &NBSP;&NBSP;&NBSP;&NBSP} static calculator getobject (String type)
{ Calculator oRes = null; switch (type) { case "+": ores = new
add ();
break; case "-":
ores = new subtract (); break; case "*":
ores = new multiply ();
break; case "/":
ores = new divide ();
break; } return
ores; &NBSP;&NBSP;&NBSP;&NBSP}} public class calculator { public virtual Int compute (int x, int y) { return 0; } public class add : calculator { public override int compute (int x, int y) { return
x + y; &NBSP;&NBSP;&NBSP;&NBSP}} public class subtract : calculator { Public override int compute (int x, int y) {
return x - y; &NBSP;&NBSP;&NBSP;&NBSP}} public class multiply : calculator { Public override int compute (int x, int y) {
return x * y; &NBSP;&NBSP;&NBSP;&NBSP}} PUBLIC&NBSP;CLASS&NBSP;DIVIDE&NBSP;:&NBSP;CALCULator { public override int compute (int x, int y) { if (y == 0) {
return 0; } return x
/ y; &NBSP;&NBSP;&NBSP;&NBSP}}
The
code should be easy to read and be implemented directly by rewriting the method, which is not explained too much.
2, the delegate method implements the simple factory pattern.
class program2 { static void main (string[] args) { #region 2. Delegates implement simple Factory mode
int x = 8, y = 2;
var ocalculator = new calculator (); var ires1 = ocalculator.compute (X, y, ocalculator.add)//Pass the method as a parameter var iRes2 =
Ocalculator.compute (x, y, ocalculator.subtract); var ires3 = ocalculator.compute (X, y,
ocalculator.multiply); var ires4 = ocalculator.compute (X, y,
ocalculator.divide); console.writeline (IRES1);
console.writeline (IRes2);
console.writeline (IRES3); console.writeline (iRes4);
#endregion console.readkey ();
&NBSP;&NBSP;&NBSP;&NBSP} public delegate int delegatecalculator (Int x, int y); Public class calculator { //passes an instance of the method in and executes it in the Compute method public int
compute (Int x, int y, delegatecalculator calculator) {
return calculator (X, y); &NBSP;&NBSP;&NBSP;&NBSP} public int add (int x, int y) { return x + y;
&NBSP;&NBSP;&NBSP;&NBSP} public int subtract (Int x, int y) { return x - y; &NBSP;&NBSP;&NBSP} public int multiply (int x, int y) { return x * y; &NBSP;&NBSP} public int divide (int x, int y) { if (y == 0) { return
0; } return x
/ y; &NBSP;&NBSP;&NBSP;&NBSP}}
Here you need to define four implementation methods add, subtract, Multiply, Divide, regardless of which class the four methods are under, as long as the parameters and return values of the four methods are consistent with the definition of the delegate. This also validates the above saying "stand at the level of the method, a very useful feature of a delegate instance is that it neither knows nor cares about the details of the class to which it encapsulates the method, and it is most important for it to be compatible with the parameters and return values of the delegate. The results are the same in both ways:
Ii. Observer Pattern: The most typical scenario for observer mode is the scene of subscribers and subscription numbers
1, a pure polymorphic way to implement the Observer mode: This code is very much inside the garden.
CLASS&NBSP;PROGRAM3 { static void main (String[] args) { // Specific theme roles are usually implemented with specific intrusion
concretesubject subject = new concretesubject (); subject.
Attach (New concreteobserver (subject, "Observer a")); subject.
Attach (New concreteobserver (subject, "observer b")); subject.
Attach (New concreteobserver (subject, "observer c")); subject.
subjectstate = "Ready"; subject.
Notify ();
console.read (); &NBSP;&NBSP;&NBSP;&NBSP}//Abstract subject class Public abstract class subject { &nbsP; private ilist<observer> observers = new list<observer> (); /// <summary> /// Add Observer
</summary> /// <param name= "Observer" ></param> public void attach (observer observer) { observers.
ADD (Observer); } /// <summary> /// Remove Observer /// </summary> /// <param name= " Observer "></param> public void detach (observer observer) { observers.
REMOVE (Observer); &NBSP;&NBSP;&NBSP;&NBSP} /// <summary> /// notices to observers /// </summary> public void notify () { foreach (observer o in observers) {
o.update (); &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP} }//Specific topic class public class Concretesubject : subject { private string subjectState; /// <summary> /// specific observer status /// </summary> public string subjectstate { get { return subjectstate; } set&nbSp { subjectstate = value; }  }}//abstract Observer class Public abstract class observer { public abstract void update ();}//Specific observer Public class
concreteobserver : observer { private string observerState;
private string name;
private ConcreteSubject subject; /// <summary> /// specific observer with a specific theme to implement /// </summary> public concretesubject subject
{ get { return subject; } set { subject = value; } &NBSP;&NBSP} public concreteobserver (Concretesubject subject, string name) { this.subject
= subject;
this.name = name; } /// <summary> /// Implement update operations /// </summary> public override for abstract observers void update () { observerstate = subject.
Subjectstate; console.writeline ("The observer ' s state of
{0} is {1} ", name, observerstate); &NBSP;&NBSP;&NBSP;&NBSP} You can see that although the separation between the observer observer and the subject subject is well achieved. But there was a call to the observer in subject's interior: Public void notify () { foreach (Observer o in observers) {&NBSP;&NBSP;&NBSp; o.update (); &NBSP;&NBSP;&NBSP;&NBSP;&NBSP}}
2, polymorphism, and delegates implement the observer pattern.
CLASS&NBSP;PROGRAM3 { static void main (String[] args) { // Specific theme roles are usually implemented with specific intrusion
concretesubject subject = new concretesubject ();
//incoming is just the way the observer passes. subject. Attach (New concreteobserver (subject, "Observer a").
Update); subject. Attach (New concreteobserver (subject, "Observer b").
Update); subject. Attach (New concreteobserver (subject, "Observer c").
Update); subject.
subjectstate = "Ready"; subject.
Notify ();
console.read (); &NBSP;&NBSP}} public delegate void observerdelegate (); Abstract Theme class Public abstract class subject { public ObserverDelegate
Observedelegate; /// <summary> /// Add Observer
</summary> /// <param name= "Observer" ></param>
public void attach (Observerdelegate observer) {
observedelegate += observer; } /// <summary> /// Remove Observer /// </summary> /// <param name= " Observer "></param> public void detach (observerdelegate observer ) { observedelegate -= observer; } /// <summary> /// Give notice to the Observer /// </summary> public void Notify () { if (observedelegate != null) {
observedelegate (); &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP} }//Specific topic class public class Concretesubject : subject { private string subjectState; /// <summary> /// specific observer status /// </summary> public string subjectstate { get { return subjectstate; } set { subjectstate = value; }  }}//
Specific Observer Public class concreteobserver { private string observerState;
private string name;
private ConcreteSubject subject; /// <summary> /// specific observer with a specific theme to implement /// </summary> public concretesubject subject
{ get { return subject; } set { subject = value; } &NBSP;&NBSP} public concreteobserver (CONCRETESUBJECT&NBSP;SUBJECT,&NBSP;STRING&NBsp;name) { this.subject =
Subject
this.name = name; } /// <summary> /// Implementation of update operations in abstract observers /// </summary> public void Update () { observerState = Subject.
Subjectstate; console.writeline ("The observer ' s state of
{0} is {1} ", name, observerstate); &NBSP;&NBSP;&NBSP;&NBSP}}
Get the result:
Advantages of this design:
(1) The method update of the notification is passed to the subject object in the form of a delegate. This subject object subject is completely isolated from the observer. Better implementation of low coupling.
(2) reduced the definition of the observer abstract class. Make the whole design more streamlined.
(3) If the design is further developed, the observer here customizes the Delegate void Observerdelegate () method of this type. For example, you need to follow the update () method to record the operation of a log. Such as:
Specific Observer Public class concreteobserver { private string observerState;
private string name;
private ConcreteSubject subject; /// <summary> /// specific observer with a specific theme to implement /// </summary> public concretesubject subject
{ get { return subject; } set { subject = value; } &NBSP;&NBSP} public concreteobserver (concretesubject subject, string name) { this.subject =
Subject
this.name = name; } /// <summary> /// Implementing update operations in abstract observers /// </summary> public void update () { observerstate = subject.
Subjectstate; console.writeline ("The observer ' s state of
{0} is {1} ", name, observerstate); &NBSP;&NBSP;&NBSP;&NBSP} public void log () {
console.writeline ("Log:update Method execution completed"); &NBSP;&NBSP;&NBSP;&NBSP}}
Then the log method can only be passed in as a delegate when the client invokes:
static void Main (string[] args)
{
//specific theme roles are usually implemented in a specific
concretesubject subject = new ConcreteSubject ();
//Incoming is just an observer's way of passing.
var obj = new Concreteobserver (subject, "Observer A");
Subject. Attach (obj. Update);
Subject. Attach (obj. LOG);
Subject. Subjectstate = "Ready";
Subject. Notify ();
Console.read ();
}
is not a little more flexible. In the case of pure polymorphism, the code changes much more when the log method is needed, as the subject specifies the call Update () method.
Third, the template method model, here take the equipment collection as an example to explain:
1, polymorphic Implementation Template method pattern:
class program4 { static void main (String[] args) {&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;VAR&NBSP;OTEM1&NBSP;=&NBSP;NEW&NBSP;DEVICEMML ()
otem1.spider ();
console.writeline ("");
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;VAR&NBSP;OTEM2&NBSP;=&NBSP;NEW&NBSP;DEVICETL2 ();
otem2.spider ();
console.readkey (); &NBSP;&NBSP;&NBSP;&NBSP}} public abstract class templetedevice { //
Template methods, do not define templates as virtual or abstract methods, avoid quilt overrides, and prevent changes in the order in which processes are executed public void spider () { console.writeline ("Start of equipment Acquisition"); this.
Login (); &nbSp; this.
Validation (); this.
SpiderByType1 (); this.
SpiderByType2 (); this.
Loginout ();
console.writeline ("Equipment collection End"); &NBSP;&NBSP;&NBSP;&NBSP} // Landing public void login () { console.writeline ("Landing"); &NBSP;&NBSP;&NBSP} // Verify public void validation ( ) { console.writeline ("Validation"); } // Collection public abstract void
SpiderByType1 ();
public abstract void spiderbytype2 (); // Cancellation &Nbsp; public void loginout () {
console.writeline ("cancellation"); &NBSP;&NBSP;&NBSP;&NBSP}}//MML type of device collection Public class devicemml : templetedevice { public override void spiderbytype1 () {
console.writeline ("MML type equipment began to collect 1"); //...  } Public override void spiderbytype2 () {
console.writeline ("MML type equipment began to collect 2"); &NBSP;&NBSP;&NBSP;&NBSP}}//TL2 type Device collection Public class devicetl2 : templetedevice { public override void spiderbytype1 () { console.writeline ("TL2 type equipment began to collect 1");
//...  } Public override void spiderbytype2 () {
console.writeline ("TL2 type equipment began to collect 2"); &NBSP;&NBSP;&NBSP;&NBSP}}
Non-abstract methods within the
Parent class are template methods, which are common to subclasses and cannot be overridden. SpiderType1 and SpiderType2 are methods that require subclass overrides. Template method Patterns define the implementation steps of an algorithm in an abstract class, defer implementation of these steps to a specific subclass, so that all subclasses reuse the code of the parent class, so the template method pattern is a technique for implementing code reuse based on inheritance.
2, after using a delegate rewrite:
class program4 { static void main (String[] args) { var otem1 = new templetedevice (
DEVICEMML.SPIDERBYTYPE1,&NBSP;DEVICEMML.SPIDERBYTYPE2);
otem1.spider ();
console.writeline (""); var otem2 = new templetedevice (
DEVICETL2.SPIDERBYTYPE1,&NBSP;DEVICETL2.SPIDERBYTYPE2);
otem2.spider ();
console.readline ();
&NBSP;&NBSP;&NBSP;&NBSP}} public delegate void devicedelegate (); Public class templetedevice { public DeviceDelegate oDelegate; public templetedevice (Params devicedelegate[] lstfunc) &NBSP;&NBSP;&NBSP;&NBSp { foreach (Var ofunc in lstfunc) {
oDelegate += oFunc; } &NBSP;&NBSP} // template methods, do not define templates as virtual or abstract methods, avoid quilt overrides, and prevent changes in the order in which processes are executed public void spider () {
console.writeline ("Equipment acquisition start"); this.
Login (); this.
Validation (); if (odelegate != null)
{ odelegate (); &NBSP;&NBSP;&NBSP;&NBSP} this.
Loginout ();
console.writeline ("Equipment collection End"); &NBSP;&NBSP;&NBSP;&NBSP} // Landing public void login () { console.writeline ("Landing"); &NBSP;&NBSP;&NBSP} // Verify public void validation ( ) { console.writeline ("Validation"); &NBSP;&NBSP} // Logoff public void loginout () { console.writeline ("Logoff"); &NBSP}}//MML type of device collection PUBLIC&NBSP;CLASS&NBSP;DEVICEMML { public static void spiderbytype1 () { console.writeline ("MML type equipment began to collect 1"); //...  } Public static void spiderbytype2 () {
console.writeline ("MML type equipment began to collect 2"); &NBSP;&NBSP;&NBSP;&NBSP}}
Collection of TL2 type equipment
public class DeviceTL2
{
public static void SpiderByType1 ()
{
Console.WriteLine ("TL2 type equipment began to collect 1");
//.......
}
public static void SpiderByType2 ()
{
Console.WriteLine ("TL2 type equipment began to collect 2");
}
}
Get the result:
The significance of optimizing template method Patterns:
(1) The inheritance relationship between subclass and parent class is lifted, and the low coupling between objects is better realized.
(2) The use of delegates can dynamically implement the combination of methods, this way more flexible, subclasses can be more flexible design of different parts of the method. The number of methods is then passed through the params, with no strict restrictions on the number of methods.
Of course, other design patterns can also be commissioned to optimize the design, bloggers here temporarily only share the similarities and differences of these three patterns. In general, delegates are unlikely to replace polymorphism to implement various patterns, but they can be combined with polymorphism to achieve a more flexible design. Through these two articles down, do not know whether you have a feeling of the delegate, commissioned this thing, heavy in combat, like swimming, if not so many times, you can never learn. The above is only the personal understanding of bloggers, may be a lot of convenience is not considered so comprehensive, I hope you will correct me.