C#中的委托delegate

委托是一种定义方法签名的类型,可以与具有兼容签名的任何方法关联。你可以通过委托调用方法。委托用于将方法参数传递给其它方法。事件处理程序就是通过委托调用的方法(这是MSDN中对委托的解释)。个人感觉C#中委托类似于C++中的函数指针,但委托又是一种特殊的类,只有方法的类。

在C#中使用委托时,需要经过这两个步骤,首先定义要使用的委托,对于委托定义它就是告诉编译器这种类型的委托表示哪种类型的方法。然后必须创建该委托的一个或多个实例。编译器在后台将创建表示该委托的一个类。

定义委托的语法如下:

    delegate void IntMethodInvoker(int x);

在这个实例中,定义了一个委托IntMethodInvoker,并制定该委托的每个实例都可以包含一个方法的引用,该方法带有一个int参数,并返回void。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。

实际上,定义一个委托实质上是定义了一个类。委托实现为派生自基类System.MulticastDelegate的类,System.MulticastDelegate又派生自基类System.Delegate。C#编译器能识别这个类,会使用委托语法。所以,可以在定义类的任何地方定义委托,也就是说可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。根据定义的可见性和委托的作用域,可以在委托的定义上应用常见的任何访问修饰符:public、private、protected等。

下面来看一个实例化委托的例子:

namespace ConsoleApplication
{
    class DelegateDemo1
    {
        //定义委托
        public delegate string GetString();

        public static void Main()
        {
            int num = 19;
            //使用关键字new用Int32的ToString方法实例化委托
            GetString getIntString = new GetString(num.ToString);
            Console.WriteLine("使用委托...");
            Console.WriteLine("num = {0}", getIntString());
            Console.WriteLine("不使用委托...");
            Console.WriteLine("num = {0}", num.ToString());
            int[] array = {1, 2, 3, 4, 5, 6};
            //另一种实力哈委托的方式,注意这里没有使用关键字new
            GetString getAnotherString = array.ToString;
            Console.WriteLine("使用委托...");
            Console.WriteLine("array = {0}", getAnotherString());
            Console.WriteLine("不使用委托...");
            Console.WriteLine("array = {0}", array.ToString());
        }
    }
}
运行结果如下:

C#中的委托delegate_第1张图片

除了为每个参数和返回类型定义一个新委托类型之外,还可以使用Action和Func委托。泛型Action委托表示应用一个void返回类型的方法。因为这个委托类存在不同的变体,所以可以传递至多16种不同的参数类型。没有泛型参数的Action类可调用没有参数的方法。Action调用带一个参数的方法,Action调用带两个参数的方法,等等。

Func委托可以以类似的方式使用。Func允许调用带返回类型的方法。与Action类似,Func也定义了不同的变体,至少也可以传递16哥参数类型和一个返回类型。Func委托类型可以调用带返回类型且无参数的方法,Func可以调用带一个参数的方法,等等。具体使用,在下面的例子中可以看到。

MSDN中有下述一段:

委托具有以下特点:

  • 委托类似于 C++ 函数指针,但它们是类型安全的。

  • 委托允许将方法作为参数进行传递。

  • 委托可用于定义回调方法。

  • 委托可以链接在一起;例如,可以对一个事件调用多个方法。

  • 方法不必与委托签名完全匹配。有关更多信息,请参见Covariance and Contravariance委托中的协变和逆变(C# 编程指南)

  • C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。这些功能统称为匿名函数。有关 Lambda 表达式的更多信息,请参见匿名函数(C# 编程指南)

下面主要看看委托将方法作为参数进行传递,个人感觉这个挺有用的,下面我们看一个实例。

namespace ConsoleApplication
{
    class DelegateDemo2
    {
        /// 
        /// 输出数组元素
        /// 
        /// 给定数组元素
        public static void PrintArray(int[] array)
        {
            for (int i = 0; i < array.Length; i++ )
            {
                Console.Write(array[i] + " ");
            }
        }
        public static void Main()
        {
            int[] array = { 12, 34, 0, 60, 25, 78, 19 };
            Console.WriteLine("Before sort...");
            PrintArray(array);
            Console.WriteLine();
            BubbleSorter.BubbleSort(array);
            Console.WriteLine("After sort...");
            PrintArray(array);
            Console.WriteLine();
        }
        
    }

    class BubbleSorter
    {
        /// 
        /// 冒泡排序算法
        /// 
        /// 给定数组元素
        public static void BubbleSort(int[] array)
        {
            int temp = 0;
            for (int i = 0; i < array.Length - 1; i++ )
            {
                //每一轮循环后都把最大的至于最后面
                for (int j = 0; j < array.Length - i - 1; j++ )
                {
                    if (array[j] > array[j + 1])
                    {
                        temp = array[j];
                        array[j] = array[j + 1];
                        array[j + 1] = temp;
                    }
                }
            }
        }
    }
}
运行结果如下:

C#中的委托delegate_第2张图片

那如果我现在不想给数字排序,我想给一个类排序怎么办?请看下面实例:

namespace ConsoleApplication
{
    class DelegateDemo3
    {
        /// 
        /// 测试用的Person类
        /// 
        public class Person
        {
            private String name;
            public String Name
            {
                get { return name; }
                set { name = value; }
            }
            private String gender;
            public String Gender
            {
                get { return gender; }
                set { gender = value; }
            }
            private String address;
            public String Address
            {
                get { return address; }
                set { address = value; }
            }

            public Person()
            {

            }

            public Person(String name, String gender, String address)
            {
                this.name = name;
                this.gender = gender;
                this.address = address;
            }
        }

        /// 
        /// Compares the given person by the name.
        /// 
        /// The person1.
        /// The person2.
        /// ture表示person1大于person2,false表示person1小于person2
        private static bool ComparePersonByName(Person person1, Person person2)
        {
            if (String.Compare(person1.Name, person2.Name) < 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// 
        /// 整形数字的比较
        /// 
        /// The num1.
        /// The num2.
        /// ture表示num1大于num2,false表示num1小于num2
        private static bool CompareNumber(int num1, int num2)
        {
            return (num1 > num2 ? true: false);
        }

        /// 
        /// 输出数组元素
        /// 
        /// The array.
        private static void PrintInfo(int[] array)
        {
            for (int i = 0; i < array.Length; i++ )
            {
                Console.Write(array[i] + " ");
            }
            Console.WriteLine();
        }

        private static void PrintInfo(Person[] people)
        {
            for (int i = 0; i < people.Length; i++ )
            {
                Console.Write(people[i].Name + " ");
            }
            Console.WriteLine();
        }

        /// 
        /// 改造后的冒泡排序
        /// 
        /// 
        /// 传入的类型为T[]的数组
        /// 有两个类型为T的参数,返回值为bool型的委托
        public static void BubbleSort(T[] array, Func compare)
        {
            //这里的default把temp设置为默认的初始化值,如果T为基本数据类型,则temp为0,如果T是类,则temp为null
            T temp = default(T);
            for (int i = 0; i < array.Length - 1; i++)
            {
                //每一轮循环后都把最大的至于最后面
                for (int j = 0; j < array.Length - i - 1; j++)
                {
                    if (compare(array[j], array[j + 1]))
                    {
                        temp = array[j];
                        array[j] = array[j + 1];
                        array[j + 1] = temp;
                    }
                }
            }
        }

        public static void Main()
        {
            int[] nums = { 14, 36, 78, 9, 55, 0, 100};
            Person[] people = new Person[4];
            people[0] = new Person("周杰伦","男","台北");
            people[1] = new Person("谭振宇","男","海南");
            people[2] = new Person("潘安","男","新疆");
            people[3] = new Person("蒋敏","男","北京");
            Console.WriteLine("排序前...");
            PrintInfo(nums);
            PrintInfo(people);

            Console.WriteLine("排序后...");
            BubbleSort(nums, CompareNumber);
            BubbleSort(people, ComparePersonByName);
            PrintInfo(nums);
            PrintInfo(people);
        }
    }
}

C#中的委托delegate_第3张图片

注意到程序中
void BubbleSort(T[] array, Func compare)
第二个参数使用的是一个委托类型,这个委托实现了对具体数组元素大小的比较,这样你传入什么样的比较方法,冒泡排序就能根据你传输的比较方法进行比较,这样任何的元素就能进行排序了。

你可能感兴趣的:(#,C#)