C# 进阶教程(一) 委托

1 委托

1.1 委托简介

委托是C#语言中的一种高级语法,其作为一种与类同级的对象,定义在命名空间内。

//委托的定义
namespace TestNameSpace
{
    public delegate void testDelegate (string text);
    public class TestClass
    {
            static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

委托是一个对象,它知道该如何调用方法,作为一个引用类型,和类是同级的,委托实例 把方法赋值给委托变量时调用者调用委托,委托调用目标方法。

1.2 委托是一种方法模板

和面向对象中的类的概念相似,我们都知道类作为一个对象的模板,各种对象都可以被描述为一个类或者继承于某个类的子类。

而委托也是一种模板,它是函数/方法的模板,如上面所看到的委托 testDelegate ,其就是一类方法的模板,其代表的是输入类型为 string ,返回类型为 void 的一类函数。其实例化的过程需要接收该类型的函数。如下方示例所示:

using System;

namespace TestNameSpace
{
    public delegate void testDelegate(string text);
    public class TestClass
    {
        static void Main(string[] args)
        {
            MethodClass methodClass = new MethodClass();//实例化类 用于引用类中存在的方法
            testDelegate testDelegate_1 = new testDelegate( methodClass.TestMethod_1);//实例化委托 方法作为委托的参数
            testDelegate testDelegate_2 = new testDelegate( methodClass.TestMethod_2);//实例化委托 方法作为委托的参数
            testDelegate_1(" 成功");
            testDelegate_2(" 成功");
        }
    }
    public class MethodClass
    {
        public void TestMethod_1(string s)
        {
            Console.WriteLine("这是第一个方法" + s);
        }
        public void TestMethod_2(string s)
        {
            Console.WriteLine("这是第二个方法" + s);
        }
    }
}

输出结果为

这是第一个方法 成功
这是第二个方法 成功

可以看到委托与类同级,委托也需要进行实例化以获得对象,委托实例化时需要的参数是与其定义相同的方法。

若想执行目标方法,可以直接借用委托并且输入方法参数,来获取目标输出。

2 Action 委托

命名空间: System

程序集: System.Runtime.dll

Action 委托是 .NET Framwork 自带的委托,在使用 Action 委托时,可以省去自定义显式委托的步骤,简化代码。

需要注意的是 :Action()委托 所接受的方法 可以一个或者多个参数,但是不能有返回值

2.1 重载1 Action()

封装一个方法,该方法不具有参数,且不具有返回值。

public delegate void Action();//这是一个官方定义的委托 是一个确定的委托名称 其参数是一个没有参数 没有返回值的方法

使用 Action作为委托,就不必再显示定义委托,下述示例,就定义了 showvalue()委托,最后使用 showvalue()委托实现了对应的方法,但是也可以直接用 Action()委托,因为它在程序集中已经被定义了,不需要再次定义。

using System;
using System.Windows.Forms;

public delegate void ShowValue();  //这里指的就是显式定义委托 ShowValue()

public class Name
{
   private string instanceName;

   public Name(string name)
   {
      this.instanceName = name;
   }
   public void DisplayToConsole()
   {
      Console.WriteLine(this.instanceName);
   }
   public void DisplayToWindow()
   {
      MessageBox.Show(this.instanceName);
   }
}
public class testTestDelegate
{
   public static void Main()
   {
      Name testName = new Name("Koani");
      ShowValue showMethod = testName.DisplayToWindow; 

      //如果使用Action委托 那么就不用显式定义 showValue 委托 
      //Action showMethod = testName.DisplayToWindow;
      //Action showMethod = () => testName.DisplayToWindow();//还可以使用 lamba 表达式
      showMethod();
   }
}

2.2 重载2 Action< T >

封装一个方法 该方法只有一个参数,且没有返回值

public delegate void Action<in T>(T obj);

T 代表委托封装的方法的参数类型,属于逆变类型参数 ,想要了解泛型逆变和协变类型参数可以参阅泛型中的协变和逆变 | Microsoft Learn

参数 T obj

此委托 Action < T >封装的方法所需的参数 obj;意思就是说,这个obj 是 委托所需方法所需的参数。

示例

以下示例演示如何使用 Action 委托来打印对象的内容 List 。 在此示例中, Print 该方法用于向控制台显示列表的内容。 此外,C# 示例还演示了使用匿名方法向控制台显示内容。 请注意,该示例不显式声明变量 Action 。 相反,它会将引用传递给采用单个参数的方法,并且不向 List.ForEach 该方法返回值,该方法的单个参数是 Action 委托。 同样,在 C# 示例中,Action不会显式实例化委托,因为匿名方法的签名与该方法预期的List.ForEach委托的Action签名匹配。

List<string> names = new List<string>();//新建泛型列表
names.Add("Bruce");
names.Add("Alfred");
names.Add("Tim");
names.Add("Richard");
// 加入4个列表元素
// Display the contents of the list using the Print method.
names.ForEach(Print);
//Lsit<T>.ForEach 函数 对List<T>中的每个元素执行指定的操作 
public void ForEach (Action<T> action); //接受 Action <T> 委托类型参数 对每个元素执行 委托中的方法

// The following demonstrates the anonymous method feature of C#
// to display the contents of the list to the console.
names.ForEach(delegate(string name)
{
    Console.WriteLine(name);
});

void Print(string s)
{
    Console.WriteLine(s);
}

/* This code will produce output similar to the following:
* Bruce
* Alfred
* Tim
* Richard
* Bruce
* Alfred
* Tim
* Richard
*/

2.3 重载 3 Action<T,T,T>

代码示例

using System;

namespace VSCodeProject
{
    class Program
    {
        static void Main(string[] args)
        {
           Test test = new Test("test");
           Action<string> action = test.Method; action(test.s);
           
           Action action2 = test.Method2; action2();//委托是一种特殊的方法
           Action<string ,string ,string> action3 = test.Method3; action3("a","b","c");
           
        }
    }
    public class Test
    {
        public string s;
        public Test(string S)
        {
            s = S;
        }
        public void Method(string s)
        {
            Console.WriteLine(s + " 这是有一个参数的委托方法");
        }
        public void Method2()
        {
            Console.WriteLine("这是无参数的委托方法");
        }
        public void Method3(string s1,string s2,string s3)
        {
            Console.WriteLine(s1 + s2 + s3 + " 这是有三个参数的委托方法");
        }
        
    }
}

输出结果

test 这是有一个参数的委托方法
这是无参数的委托方法
abc 这是有三个参数的委托方法