C#进阶-委托(Delegate)

举报
Damon小智 发表于 2024/05/29 10:07:22 2024/05/29
【摘要】 类似于C或C++中的函数指针,委托是C#中的函数指针,是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。本篇文章将讲解C#里委托的类型及如何使用。委托的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。

1. 声明和实例化委托

委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同参数和返回值(或一样没有参数或返回值)的方法。

修饰符 delegate 返回值类型 委托名(参数列表); //声明委托
委托名 委托对象名 = new 委托名(方法名); //实例化委托
namespace DelegateDemo
{
    class Program
    {
        /*声明委托*/
        public delegate void FuncDelegate(); //无参无返回值委托
        public delegate string FuncDelegateString(string x); //有参有返回值委托

        static void Main(string[] args)
        {
            /*实例化委托*/
            FuncDelegate funcDelegateA = new FuncDelegate(Hello);
            funcDelegateA();
            FuncDelegateString funcDelegateB = new FuncDelegateString(Hello);
            funcDelegateB("xxx");
        }

        public static void Hello()
        {
            Console.WriteLine("Hello");
        }

        public static string Hello(string x)
        {
            Console.WriteLine("Hello, " + x);
            return "Hello";
        }
    }
}

输出结果:

Hello
Hello, xxx

2. 委托数组

委托数组存储相同委托的方法,可以通过遍历数组依次执行里面委托的方法。

委托名[] 委托对象名 = {委托的方法1, 委托的方法2, ...}
namespace DelegateDemo
{
    class Program
    {
        /*声明委托*/
        public delegate void FuncDelegate(); //无参无返回值委托
        public delegate string FuncDelegateString(string x); //有参有返回值委托

        static void Main(string[] args)
        {
            //无参数无返回值委托数组
            FuncDelegate[] funcArrayA = { Hello, World };
            foreach (FuncDelegate func in funcArrayA)
            {
                func();
            }

            //带参数带返回值的委托的数组
            FuncDelegateString[] funcArrayB = { Hello, World };
            foreach (FuncDelegateString func in funcArrayB)
            {
                FuncArray(func, "Damon");
            }
        }

        public static void FuncArray(FuncDelegateString func, string value)
        {
            Console.WriteLine("");
            Console.WriteLine("方法 " + GetFunctionName(func) + " 返回值是 " + func(value));
        }

        public static void Hello()
        {
            Console.WriteLine("Hello");
        }

        public static void World()
        {
            Console.WriteLine("World");
        }

        public static string Hello(string x)
        {
            Console.WriteLine("Hello, " + x);
            return "Hello";
        }

        public static string World(string x)
        {
            Console.WriteLine(x + "'s World");
            return x;
        }
    }
}

输出结果:

Hello
World
Hello, Damon
方法 Hello 返回值是 Hello
Damon's World
方法 World 返回值是 Damon

3. Action和Func

ActionFunc都是.NET Framework内置的泛型委托,免声明直接实例化调用。

  • Action 是.NET Framework内置的泛型委托,要求委托必须无返回值:
Action<参数类型> 委托对象名 = 方法名 //有参情况
Action 委托对象名 = 方法名 //无参情况
  • Func 是.NET Framework内置的泛型委托,支持有参有返回值:
Func<返回类型> 委托对象名 = 方法名
Func<参数, 返回类型> 委托对象名 = 方法名
Func<参数, 参数, 返回类型> 委托对象名 = 方法名 //更多参数同理
namespace DelegateDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //Action是.NET Framework内置的泛型委托,要求委托必须无返回值
            Action[] actions = { Hello, World };
            foreach (Action func in actions)
            {
                func();
            }

            //Func是.NET Framework内置的泛型委托,支持有参有返回值
            Func<int> func1 = ReturnIntValue;

            Func<int, string> func2 = World;

            Func<string, string, string> func3 = World;

            Func<int, string>[] funcArrayC = { World };
            foreach (Func<int, string> func in funcArrayC)
            {
                FuncArray(func, 114514);
            }
        }

        public static void FuncArray(Func<int, string> func, int value)
        {
            Console.WriteLine("");
            Console.WriteLine("方法 " + GetFunctionName(func) + " 返回值是 " + func(value));
        }

        public static void Hello()
        {
            Console.WriteLine("Hello");
        }

        public static void World()
        {
            Console.WriteLine("World");
        }

        public static string World(int x)
        {
            Console.WriteLine(x + "'s World");
            return "World(int x)";
        }

        public static int ReturnIntValue()
        {
            return 1;
        }
    }
}

输出结果:

Hello
World
114514's World
方法 World 返回值是 World(int x)

4. 匿名委托

匿名方法的定义方式如下:

Func<T> 委托对象名 = delegate(方法参数){ 方法体 };
namespace DelegateDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //匿名方法
            Func<int, string> AnonymousDelegate = delegate (int x)
            {
                return "1";
            };
        }
    }
}

5. 委托的多播

委托对象可使用 “+” 运算符进行合并相同类型的委托,也可使用 “-” 运算符移除任一合并委托中的委托。一个合并委托调用它所合并的N个委托。在实际工作中,我们常常创建一个委托被调用时要调用的方法的调用列表。

委托名 委托对象A;
委托名 委托对象B = new 委托名(方法名);
委托名 委托对象C = new 委托名(方法名);
委托对象A = 委托对象B;
委托对象A += 委托对象C;
委托对象A -= 委托对象C;
namespace DelegateDemo
{
    class Program
    {
        /*声明委托*/
        public delegate void FuncDelegate(); //无参无返回值委托
        public delegate string FuncDelegateString(string x); //有参有返回值委托

        static void Main(string[] args)
        {
            //委托的多播
            FuncDelegateString fds;
            FuncDelegateString fds1 = new FuncDelegateString(Hello);
            FuncDelegateString fds2 = new FuncDelegateString(World);
            fds = fds1;
            fds += fds2; //表示在委托列表里添加
            // fds -= fds2; //表示从委托列表里去除
            fds("Damon");

            //第二种写法
            FuncDelegate fb1 = new FuncDelegate(StaticFeedbackFunc); //这里直接调用的静态方法
            Program p = new Program();
            FuncDelegate fb2 = new FuncDelegate(p.FeedbackFunc); //非静态方法需要实例化调用
            FuncDelegate fbChain = null;
            fbChain = (FuncDelegate)Delegate.Combine(fbChain, fb1); //和+=一样
            fbChain = (FuncDelegate)Delegate.Combine(fbChain, fb2);
            fbChain = (FuncDelegate)Delegate.Remove(fbChain, new FuncDelegate(p.FeedbackFunc)); //和-=一样
        }

        public static string Hello(string x)
        {
            Console.WriteLine("Hello, " + x);
            return "Hello";
        }

        public static string World(string x)
        {
            Console.WriteLine(x + "'s World");
            return x;
        }

        public static void StaticFeedbackFunc()
        {
            Console.WriteLine("StaticFeedbackFunc()");
        }

        public void FeedbackFunc()
        {
            Console.WriteLine("FeedbackFunc()");
        }
    }
}

输出结果:

Hello, Damon
Damon's World
StaticFeedbackFunc()

6. 事件

事件(Event)是类或者对象向其他类或对象通知发送的事情的一种特殊签名的委托。事件使用event关键词来声明,它的返回值是一个委托类型。

public event 委托类型 事件名;

namespace DelegateDemo
{
    public delegate void FuncDelegate(); //无参无返回值委托

    class Program
    {
        static void Main(string[] args)
        {
            //事件
            DelegateEvent delegateEvent = new DelegateEvent();
            delegateEvent.DelegateEvent += Hello; //类似于
            delegateEvent.DelegateEvent += World;
            delegateEvent.DelegateEvent -= World;
        }

        public static void Hello()
        {
            Console.WriteLine("Hello");
        }

        public static void World()
        {
            Console.WriteLine("World");
        }
    }

    class DelegateEvent
    {
        //声明事件,event可以让外部无法直接访问这个委托
        public event FuncDelegate DelegateEvent = null;
    }
}

总结

通过本篇文章,我们学习了C#中委托的声明和使用,包括基本的委托、委托数组、内置的泛型委托ActionFunc、匿名委托、委托的多播以及事件的使用。委托是C#中非常强大且灵活的功能,通过多加练习和在项目中的实际应用,您会对其有更深的理解和掌握。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。