C#中的委托和事件(二)

来源:互联网 发布:a股大数据公司 编辑:程序博客网 时间:2024/05/16 17:00

在C#中声明委托

    在C#中使用一个类时,分两个阶段。首先需要定义这个类,即告诉编译器这个类由什么字段和方法组成。然后(除非只使用静态方法)实例化类的一个对象。使用委托,也需要经过这两个步骤。首先定义要使用的委托,对于委托,定义它就是告诉编译器这种类型的委托代表了那种类型的方法,然后创建该委托的一个或多个实例。

    定义委托的语法如下:

          delegate void VoidOperation(uint x);

     在这个示例中,定义了一个委托VoidOperation,并指定该委托的每个实例都包含一个方法的细节,该方法带有一个uint参数,并返回void。理解委托的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所代表的方法的全部细节。

 

    提示:

     理解委托的一种好方式是吧委托的作用当作是给方法签名指定名称。

     假定要顶一个委托TwoLongsOp,该委托代表的函数有两个long型参数,返回类型为double。可以编写如下代码:

            delegate double TwoLongsOp(long first,long second);

     或者定义一个委托,他代表的方法不带参数,返回一个string型的值,则可以编写如下代码:

             delegate string GetString();

     其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate。因为定义委托基本上是定义一个外部定义,还可以在冥冥空间中把委托定义为顶层对象。根据定义的可见性,可以在委托定义上添加一般的饿访问修饰符:public、private 和protected等:

             public delegate string GetString();

     注意:实际上,“定义一个委托”是指“定义一个新类”。委托实现为派生于基类System.MulticastDelegate的类,System.MulticastDelegate又派生于基类System.Delegate。C#编译器知道这个类,会使用其委托语法,因此我们不需要了解这个类的具体执行情况,这是C#与基类共同合作,使编程更易完成的另一个示例。

定义好委托后,就可以创建它的一个实例,以存储特定方法的细节。

     此处,在术语方面有一个问题。类有两个不同的术语:“类”表示叫广义的定义,“对象”表示类的实例。但委托只有一个术语。在创建委托的实例时,所创建的委托的实例仍称为委托。您需要从上下文中确定委托的确切含义。

 

在C#中使用委托

        下面的代码段说明了如何使用委托。这是在int上调用ToString()方法的一种相当冗长的方式:

         private delegate string GetAString();

         static void Main(string[] args)

         {

                  int x = 40;

                  GetAString firstStringMethod = new GetAString(x.ToString);

                  Console.WriteLine("String is "+ firstStringMethod());

         在这段代码中,实例化了类型为GetAString的一个委托,并对它进行初始化,使它引用整型变量x的ToString()方法。在C#中,委托在语法上总是带有一个参数的构造函数将,这个参数就是委托引用的方法。在各方法必须匹配最初定义委托时的签名。所以在这个示例中,如果用不带参数、返回一个字符串的方法发来初始化firstStringMethod,就会产生一个编译错误。注意,int.ToString()是一个实例方法(不是静态方法),所以需要制定实例(x)和方法名来正确初始化委托。

          下一行代码使用这个委托来显示字符串。在任何代码中,都应提供委托实例的名称,后面的括号应包含调用该委托中的方法时使用的参数。所以在上面的代码中,Console.WriteLine()语句完全等价于注释语句中的代码行。

         委托的一个特征是它们的类型是安全的,可以确保被调用的方法签名是正确的。但有趣的是,它们不关心调用该方法的是什么类型的对象,甚至不考虑该方法的静态方法,还是实例方法。

         给定委托的实力可以表示任何类型的任何对象上的实例方法或静态方法——只要方法的签名匹配与委托的签名即可。

为了说明这一点,我们扩展了上面的代码,让它使用firstStringMethod委托在另一个对象上调用其他两个方法,其中一个方法是实例方法,另一个方法是静态方法。为此,再次使用前面定义的Currency结构。

struct Currency

{

public uint Dollars;

public ushort Cents;

 

public Currency(uint dollars,ushort cents)

{

this.Dollars = dollars;

this.Cents = cents;

}

public override string ToString()

{

return string.Format("${0}.{1,-2:00}",Dollars,Cents);

}

public static explicit operator Currency(float value)

{

checked

{

uint dollars =(uint)value;

ushort cents =(ushort)((value-dollars)*100);

return new Currency(dollars,cents);

}

}

 

public static implicit operator float(Currency value)

{

return value.Dollars + (value.Cents/100.0f);

}

public static implicit operator Currency(uint value)

{

return new Currency(value,0);

}

public static implicit operator uint(Currency value)

{

return value.Dollars;

}

}

Currency 结构已经有了自己的ToString()重载方法。为了说明如何使用带有静态方法的委托,再增加一个静态方法,起签名与Currency的签名相同:

struct Currency

{

public static string GetCurrencyUint()

{

return "Dollar";

}

}

下面就可以使用GetAString实例,代码如下所示:

private delegate string GetAString();

static void Main(string[] args)

{

int x = 40;

GetAString firstStringMethod = new GetAString(x.ToString);

Console.WriteLine("String is "+ firstStringMethod());

Currency balance = new Currency(34,50);

firstStringMethod = new GetAString(balance.ToString);

Console.WriteLine("String is "+ firstStringMethod());

firstStringMethod = new GetAString(Currency.GetCurrencyUnit);

Console.WriteLine("String is "+firstStringMethod());

}

      这段代码说明了如何通过委托来调用方法,然后重新给委托指定在类的不同实例上执行的不同方法,甚至可以指定静态方法,或者在类的不同类型的实例上执行的方法,只要每个方法的签名匹配与委托定义即可。

但是我们还没有说明把一个委托传递给另一个方法哦具体过程,也没有给出任何有用的结果。调用int和Currency对象的ToString()的方法要比使用委托直观得多!在真正领会到委托的用途前,需要用一个相当复杂的实例来说明委托的本质。下面就是两个委托的示例。第一个示例仅使用委托来调用两个不同的操作,说明了如何把委托传递给方法,如何使用委托数组,但这仍没有很好地说明没有委托,就不能完成很多工作。第二个实例就复杂得多了,他又一个类BubbleSorter,执行一个方法,按照升序排列一个对象数组,这个类没有委托是很难编写出来的。

 

 

原创粉丝点击