Detailed Explanation of c Delegation

  • 2021-12-04 19:29:25
  • OfStack

Delegate is of 1 type. Delegates in C # are object-oriented and type-safe. When you create an instance of a delegate, the instance you create contains a call list that can contain multiple methods. Each method is called a calling entity. The calling entity can be a static method or an instance method. If it is an instance method, the calling entity contains an instance that calls the instance method. A delegate does not care about the class to which the method it calls belongs, it only cares about whether the called method is compatible with the type of the delegate. Here is a code example:


using System;
namespace LycheeTest{
 public delegate void D(int a, int b);
 public class Test {
 public D myDelegate;
 public Test() {
  myDelegate = new D(Show1);
 }
 private static void Show1(int a, int b) {
  Console.WriteLine(" Method  Show1  Is called, and the value of the two arguments is: {0}", a + b);
 }
 private void Show2(int a, int b) {
  Console.WriteLine(" Method  Show2  Is called, and the value of the two arguments is: {0}", a + b);
 }
 private void Show3(int a, int b) {
  Console.WriteLine(" Method  Show3  Is called, and the value of the two arguments is: {0}", a + b);
 }
 }
 public class Program {
 static void Main(string[] args) {
  Test myT = new Test();
  myT.myDelegate(33, 22);
  Console.ReadKey();
 }
 }
}

This code demonstrates the simplest form of delegation. Delegate types can be defined outside or inside a class. This code is defined outside the class. Line 3 defines a delegate type, the key of which is delegate, preceded by the access modifier of the delegate type. Keyword is followed by the return type of the delegate type, which specifies that the return type of a method compatible with the delegate type must be the same. The return type is followed by the name of the delegate type. Next is a list of formal parameters, which specifies that methods compatible with delegate types must have the same type and number of parameters. Line 5 defines a delegate type variable, which is an instance field with public access. Note that the delegate type field must have access 1 that is lower than or the same as the delegate type. Lines 9, 12, and 15 define three methods. Line 9 is a static method. Because this code demonstrates the simplest delegate usage, only the static method is used. In the constructor in Line 6, you instantiate the variable of delegate type, notice that adding a method to the invocation list of the delegate variable only requires passing the method name to its constructor. This is the most basic way to add calling methods to delegates. Line 21 defines an instance of the Test class, and then line 22 calls the delegate member of the class. When calling a delegate member, you need to pass arguments to its formal parameter list. This is how to use the most basic delegate. The execution result of this code is as follows:

方法 Show1 被调用,两个实参相加的值是:55

Here is another way to use a delegate type. The example code is as follows:


using System;
namespace LycheeTest {
 public delegate void D(int a, int b);
 public class Test {
 public static void Show1(int a, int b) {
  Console.WriteLine(" Method  Show1  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Show2(int a, int b) {
  Console.WriteLine(" Method  Show2  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Show3(int a, int b) {
  Console.WriteLine(" Method  Show3  Is called, and the value of the two arguments is: {0}", a + b);
 }
 }
 public class Program {
 static void Main(string[] args) {
  Test myT = new Test();
  D myDelegate = new D(Test.Show1);
  D myDelegate1 = new D(myT.Show2);
  D myDelegate2 = new D(myT.Show3);
  myDelegate(22, 33);
  myDelegate1(33, 44);
  myDelegate2(55, 66);
  Console.ReadKey();
 }
 }
}

This code removes the delegate type field from the class and treats the delegate type as a class. In the class that contains the entry point method, first line 17 defines and instantiates a variable of the Test class. Because the instance method of a class is passed to a delegate, an instance of the class must exist to reference the instance method of the class. Line 18 defines a variable of delegate type and instantiates it. Note here that since the delegate is not a member of the class, passing a static method to its constructor requires a reference by the class name. Line 19 also defines a variable of delegate type, which needs to be referenced by an instance of the class when passing an instance method to it. The situation of line 20 is the same as line 19, code 1. When passing a method to a delegate, you need to pass the method name instead of the formal parameter list of the method. Lines 21 through 23 are the call to the delegate, for which the arguments of the method are passed. The execution result of this code is as follows:


 Method  Show1  Is called, and the value of the two arguments is: 55 
 Method  Show2  Is called, and the value of the two arguments is: 77 
 Method  Show3  Is called, and the value of the two arguments is: 121

Access modifiers for delegates

The access modifiers that can be used when a delegate is outside of a class include public and internal. If nothing is written, the default is internal. The access modifiers that can be used when a delegate is inside a class include public, protected, internal, protected


using System;
namespace LycheeTest{
 public class Test {
 protected delegate void D(int a, int b);
 private delegate void D1(int a, int b);
 protected internal delegate void D2(int a, int b);
 internal delegate void D3(int a, int b);
 private D myD;
 private D1 myD1;
 private D2 myD2;
 private D3 myD3;
 public Test() {
  myD = new D(Show1);
  myD1 = new D1(Show1);
  myD2 = new D2(Show1);
  myD3 = new D3(Show1);
 }
 public static void Show1(int a, int b) {
  Console.WriteLine(" Method  Show1  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Show2(int a, int b) {
  Console.WriteLine(" Method  Show2  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Show3(int a, int b) {
  Console.WriteLine(" Method  Show3  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Use() {
  myD(11, 12);
  myD1(22, 45);
  myD2(55, 78);
  myD3(345, 100);
 }
 }
 class Test1: Test {
 private D Test1D;
 private D2 Test1D2;
 private D3 Test1D3;
 public Test1() {
  Test1D = new D(Test.Show1);
  Test1D2 = new D2(Test.Show1);
  Test1D3 = new D3(Test.Show1);
 }
 public void Use1() {
  Test1D(22, 45);
  Test1D2(44, 45);
  Test1D3(77, 78);
 }
 }
 public class Program {
 static void Main(string[] args) {
  Test1 myT1 = new Test1();
  myT1.Use();
  myT1.Use1();
  Console.ReadKey();
 }
 }
}

Line 4 of the code defines the delegate type inside the class, which is defined as a member of the class, and the access permission is protected, which can be accessed inside the class or by derived classes. The delegate type defined in line 5 of the code, the access permission is private, and it can only be accessed internally by this class. The delegate type for the protected internal access permission defined in line 6 of the code can be accessed by this assembly and by derived classes, regardless of which assembly the derived class resides in. The delegate type defined in line 7 is internal, which can only be accessed by this assembly. Because all of these delegate types can be accessed internally in this class, lines 10 through 13 define their variables. The instance constructor in Line 12 instantiates the variables of these four delegate types and adds the method Show1 to their invocation list. Show1 is a static method, but the class name reference is not required when passing in the constructor of the delegate type inside the class. Line 27 defines the instance method, calls these four delegates inside the method, and passes in arguments for them. Line 34 defines another class, which inherits from the base class Test. Because only D, D2, and D3 can be accessed by derived classes in the base class, lines 35 through 37 define their variables. Note that although they are of the same type as the delegate variables in the base class, they are different delegates. In the instance constructor in line 38, we create instances of these three delegate-type variables and add methods to their call list. Because the static method Show1 is also inherited by derived classes, the method names passed in here can or can not be referenced by class names. Line 43 defines an instance method that calls these three delegates internally and passes in arguments. Line 51 defines an instance of the derived class, and then calls the instance methods Use and Use1. The execution result of this code is as follows:


 Method  Show1  Is called, and the value of the two arguments is: 23 
 Method  Show1  Is called, and the value of the two arguments is: 67 
 Method  Show1  Is called, and the value of the two arguments is: 133
 Method  Show1  Is called, and the value of the two arguments is: 445 
 Method  Show1  Is called, and the value of the two arguments is: 67 
 Method  Show1  Is called, and the value of the two arguments is: 89 
 Method  Show1  Is called, and the value of the two arguments is: 155

Because the access rights for D and D2 are defined as protected and protected internal. So let's verify that they are accessible in other assemblies. First, remove the class that contains the Main method from this code, and then change it to a class library in its project properties. Next, create a new console project and physically reference this class library. The code for the console project is as follows:


using System;
using LycheeTest;
namespace LycheeTest1{
 class Program: Test {
 private D pD;
 private D2 pD2;
 public Program() {
  pD = new D(Show1);
  pD2 = new D2(Show1);
 }
 public void Use3() {
  pD(34, 33);
  pD2(12, 11);
 }
 static void Main(string[] args) {
  Program p = new Program();
  p.Use3();
  Console.ReadKey();
 }
 }
}

Because the namespace of Line 3 and the namespace of the class library are two separate namespaces, their members are not in the same namespace. Therefore, when you refer to a member of one namespace within another namespace, you need to add the name of another namespace for reference. For the convenience of coding, the second line of code first references the namespace of the class library. Line 4 defines a class that inherits from the base class Test. Because it is a derived class, it is accessible to both delegate types D and D2. Line 5 and Line 6 define two variables for D and D2, respectively. The instance constructor in Line 7 instantiates these two variables and passes them into the method Show1. Because the Show1 method is inherited, there is no need for a class name reference here. Line 11 defines an instance method that calls the two delegates and passes them arguments. Line 16 defines an instance of this class and calls the instance method Use3. The execution result of this code is as follows:


 Method  Show1  Is called, and the value of the two arguments is: 67
 Method  Show1  Is called, and the value of the two arguments is: 23

The delegate types D2 and D3 in the class Test both have internal permissions. Now verify that under 1, they are accessible to a non-derived class in the same 1 assembly. First change the class library back to the console project, and then add a class that is independent of the Test class. They are only located in one assembly and have no inheritance relationship with each other. The code is as follows:


using System;
namespace LycheeTest {
 public class Test {
 protected delegate void D(int a, int b);
 private delegate void D1(int a, int b);
 protected internal delegate void D2(int a, int b);
 internal delegate void D3(int a, int b);
 private D myD;
 private D1 myD1;
 private D2 myD2;
 private D3 myD3;
 public Test() {
  myD = new D(Show1);
  myD1 = new D1(Show1);
  myD2 = new D2(Show1);
  myD3 = new D3(Show1);
 }
 public static void Show1(int a, int b) {
  Console.WriteLine(" Method  Show1  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Show2(int a, int b) {
  Console.WriteLine(" Method  Show2  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Show3(int a, int b) {
  Console.WriteLine(" Method  Show3  Is called, and the value of the two arguments is: {0}", a + b);
 }
 public void Use() {
  myD(11, 12);
  myD1(22, 45);
  myD2(55, 78);
  myD3(345, 100);
 }
 }
 class Test1 {
 private Test.D2 tD2;
 private Test.D3 tD3;
 public Test1() {
  tD2 = new Test.D2(Test.Show1);
  tD3 = new Test.D3(Test.Show1);
 }
 public void Use3() {
  tD2(34, 33);
  tD3(22, 21);
 }
 }
 public class Program {
 static void Main(string[] args) {
  Test1 myT1 = new Test1();
  myT1.Use3();
  Console.ReadKey();
 }
 }
}

In this code, the original class Test has not been modified. On line 35, you define a class that is independent of the Test class. Their relationship is limited to being in the same assembly. Lines 36 and 37 define two variables for delegate types D2 and D3. Note here that because these two classes are not inherited, you need to use the class name of the Test class to refer to these two delegate types in the Test class. Line 38 is the instance constructor, where the delegate is instantiated. When you instantiate a delegate type, you still need to refer to the delegate type name with the class name, as do the passed method names. Line 42 defines an instance method, which calls the delegate and passes in arguments for it. Line 49 defines an instance of the class Test1, and line 61 calls the instance method of the class. The execution result of this code is as follows:


 Method  Show1  Is called, and the value of the two arguments is: 67
 Method  Show1  Is called, and the value of the two arguments is: 43

Related articles: