C#学习笔记【九】——委托之一

9.1委托的声明与赋值

委托(delegate)是一种存储函数引用的类型。

委托的定义指定了一个返回类型和一个参数列表(告诉编译器这个委托可以指向哪些类型的方法)。

定义了委托之后,就可以创建该委托的实例(声明该委托类型的变量),接着就可以把一个返回类型和参数列表跟委托一样的函数赋值给这个变量。

委托的使用分两步:

   定义

   声明(变量)

结构体,枚举的使用同上都分为定义和声明。整数类型数组类型字符串类型都是直接声明变量的,因为类型的定义已经完成了(CLR中已经完成定义)。

namespace c_sharp_001

{

    //委托的定义与函数类似,区别在于:

    //定义委托要加delegate关键字

    //委托的定义不需要结构体      

    public delegate double MyDelegate(double param1, double param2);

    class Program

{

             //委托的定义也可也在class里

            private delegate string GetAString();

        static double Multiply(double param1, double param2)

        {

            return param1 * param2;

        }

        //定义一个Main方法

        static void Main(string[] args)

        {

            MyDelegate de;//利用委托的定义声明一个变量

            de = Multiply;//给一个委托变量赋值时(委托变量指向一个函数),返回值和参数列表必须一样

            Console.WriteLine(de(5.0, 2.0));


                int x = 10;

                 //GetAString getXString = new GetAString(x.ToString);//把方法名给一个委托的构造方法                                                                    //getXString指向了x中的ToString方法

                   GetAString getXString = x.ToString;

                 string s = getXString();//把方法名直接给委托的实例

                 //string s = getXString.Invoke();//通过Invoke方法调用getXstring所引用的方法                              Console.WriteLine(s);

            Console.ReadKey();

        }

    }

}

namespace c_sharp_practice04

{

    class Program

    {

        static void Main(string[] args)

        {

            //使用委托类型作为方法的参数

            PrintString method = Method1;

            PrintStr(method);

            method = Method2;

            PrintStr(method);

            Console.ReadKey();

        }

        private delegate void PrintString();

        static void PrintStr(PrintString print)

        {

            print();

        }

        static void Method1()

        {

            Console.WriteLine("Method1");

        }

        static void Method2()

        {

            Console.WriteLine("Method2");

        }

    }

}

9.2预定义的委托类型

9.2.1Action委托

    Action委托引用了一个无返回值的方法,它可以通过泛型(传递0~16个参数类型)去指定Action指向的方法的多个参数类型。

    Action

    Action<in T>

    Action<in T1,in T2>

    Action<in T1,in T2 ....  inT16>

namespace c_sharp_practice04

{

    class Program

    {

        static void PrintString()

        {

            Console.WriteLine("PrintString");

        }

        static void PrintString(string str)

        {

            Console.WriteLine(str);

        }

        static void PrintInt(int i)

        {

            Console.WriteLine(i);

        }

        static void Print(int i,int j,string str)

        {

            Console.WriteLine(i+j+str);

        }

        static void Main(string[] args)

        {

            Action a = PrintString;//Action是系统内置(预定义)的委托类型,它可以指向一个没有参数,没有返回                               //值的方法

            Action<int> b = PrintInt;//在Action后指定一个泛型,就可以指定Action委托类型所指向的方法的参数

            Action<string> c = PrintString;//定义了两个PrintString方法,系统会自动寻找匹配的方法

            Action<int, int, string> d=Print;

            d(1, 2, "是输出的和");

            Console.ReadKey();

        }

    }

}
9.2.2Func委托

    Func引用了一个带有一个返回值的方法,它可以传递0~16个参数类型,和一个返回类型。

    Func<out TResult>

    Func<in T,out TResult>

    Func<int T1,inT2,,,,,,in T16,out TResult>

namespace c_sharp_practice04

{

    class Program

    {

        static int Text1()

        {

            return 1;

        }

        static int Text2(string str)

        {

            Console.WriteLine(str);

            return 1;

        }

        static void Main(string[] args)

        {

            Func<int> a = Text1;//Func中的泛型指定的是方法的返回类型

            Func<string, int> b = Text2;//Func后可以有0~16个参数类型和一个返回类型(在最后)

        }

    }

}

9.2.3用委托扩展冒泡排序

namespace c_sharp_practice04

{

    class Employee

    {

        public string Name { get; private set; }

        public int Salary { get; private set; }


        public Employee(string name,int salary)

        {

            this.Name = name;

            this.Salary = salary;

        }

        public static bool Compare(Employee e1,Employee e2)

        {

            if (e1.Salary > e2.Salary) return true;

            return false;

        }

        public override string  ToString()

        {

            return Name + ":" + Salary;

        }

    }

}

namespace c_sharp_practice04

{

    class Program

    {

        //只能对一种类型的数据排序

        static void Sort(int[] sortArray)

        {

            bool swapped = true;

            do

            {

                swapped = false;

                for (int i = 0; i < sortArray.Length - 1; i++)

                {

                    if (sortArray[i] > sortArray[i + 1])

                    {

                        int temp = sortArray[i];

                        sortArray[i] = sortArray[i + 1];

                        sortArray[i + 1] = temp;

                        swapped = true;

                    }

                }

            } while (swapped);

        }

        //通过委托,扩展为各类型数据通用的冒泡排序

        static void CommonSort<T>(T[] sortArray,Func<T,T,bool> compareMethod)

        {

            bool swapped = true;

            do

            {

                swapped = false;

                for (int i = 0; i < sortArray.Length - 1; i++)

                {

                    if (compareMethod(sortArray[i],sortArray[i+1]))

                    {

                        T temp = sortArray[i];

                        sortArray[i] = sortArray[i + 1];

                        sortArray[i + 1] = temp;

                        swapped = true;

                    }

                }

            } while (swapped);

        }

        static void Main(string[] args)

        {

            Employee[] employees = new Employee[]

            {

                new Employee("asdf",120),

                new Employee("wdft",999),

                new Employee("qadg",345),

                new Employee("ipjk",12434),

                new Employee("cvnm",22),

                new Employee("egyu",2324)

            };

            CommonSort<Employee>(employees, Employee.Compare);

            foreach(var emp in employees)

            {

                Console.WriteLine(emp);//默认调用ToString方法

            }

            Console.ReadKey();

        }

    }

}

9.2.4多播委托

    前面使用的委托都只包含一个方法的调用,但是委托也可以包含多个方法,这种委托叫做多播委托。使用多播委托就可以按照顺序调用多个方法,多播委托只能得到调用的最后一个方法的(返回)结果,所以一般我们把多播委托的返回类型声明为void。

    Action action1 = Test1;

    action2+=Test2;

    action2-=Test1;

    多播委托包含一个逐个调用的委托集合,如果通过委托调用的其中一个方法抛出异常,整个迭代就会停止。

namespace c_sharp_practice04

{

    class Program

    {

        static void Text1()

        {

            Console.WriteLine("Text1");

        }

        static void Text2()

        {

            Console.WriteLine("Text2");

        }

        static void Main(string[] args)

        {

            Action a = Text1;

            a += Text2;//添加一个委托的引用

            a();

            a -= Text1;//

            Console.WriteLine("-----");

            a();

            a -= Text2;

            //a();//当一个委托没有指向任何一个方法,调用的时候出现异常null

            Console.ReadKey();

        }

    }

}

    取得多播委托中所有方法的委托。

    Action a1 = Method1;

    a1+=Method2;

    Delegate[] delegates=a1.GetInvocationList();

    foreach(delegate d in delegates){

        //d();

        d.DynamicInvoke(null);

    }

    遍历多播委托中所有的委托,然后单独调用

namespace c_sharp_practice04

{

    class Program

    {

        static void Text1()

        {

            Console.WriteLine("Text1");

        }

        static void Text2()

        {

            Console.WriteLine("Text2");

        }

        static void Main(string[] args)

        {

            Action a = Text1;

            a += Text2;//添加一个委托的引用

            Delegate[] delegates = a.GetInvocationList();//取得多播委托中的所有委托

            foreach(Delegate de in delegates)

            {

                de.DynamicInvoke();//遍历取得的所有委托,单独调用

            }

            Console.ReadKey();

        }

    }

}

9.2.5匿名委托

    前面我们使用委托,都是先定义一个方法,然后把方法给委托的实例。但还有另外一种使用委托的方式,不用去定义一个方法,应该说是使用匿名方法(方法没有名字)。

Func<int, int, int> plus = delegate (int a, int b) {//任何使用委托变量的地方都可以用匿名方法赋值

    int temp = a + b;

    return temp;

    };

int res = plus(34, 34);

Console.WriteLine(res);

    在这里相当于直接把要引用的方法直接写在了后面,优点是减少了要编写的代码,减少代码的复杂性。多用于回调。

9.2.6Lambda表达式

    可以使用Lambda表达式代替匿名方法。只要有委托参数类型的地方就可以使用Lambda表达式。9.2。5的例子可以修改为:

Func<int, int, int> plus = (arg1, arg2) =>

{

    int temp = arg1 + arg2;

    return temp;

};

int res = plus(34, 34);

Console.WriteLine(res);  

   Lambda运算符“=>”的左边列出了需要的参数,如果是一个参数可以直接写a=>(参数名自己定义),如果多个参数就使用括号括起来,参数之间以,间隔。

    如果Lambda表达式的实现代码中需要多条语句,就必须添加花括号和return语句。但如果Lambda表达式只有一条语句,在方法快内就不需要花括号和return语句,编译器会自动添加return语句。

Func<double, double> square = x => x * x; 


Func<double, double> square = x =>

{

    return x * x;

};  

    通过Lambda表达式可以访问Lambda表达式块外部的变量。这是一个非常好的功能,但如果不能正确使用,也会非常危险。示例:

int somVal = 5;

Func<int, int> f = x => x + somVal;

Console.WriteLine(f(3));//8

somVal = 7;

Console.WriteLine(f(3));//10

    这个方法的结果,不但受到参数的控制,还受到somVal变量的控制,结果不可控,容易出现编程问题,用的时候要谨慎。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值