C#中通过委托来调用对象方法的基本过程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#中通过委托来调用对象方法的基本过程相关的知识,希望对你有一定的参考价值。

delegate翻译过来是委托!

在C#中使用一个类时,分两个阶段。首先需要定义这个类,即告诉编译器这个类由什么字段和方法组成。然后(除非只使用静态方法)实例化类的一个对象。使用委托时,也需要经过这两个步骤。首先定义要使用的委托,对于委托,定义它就是告诉编译器这种类型代表了哪种类型的方法,然后创建该委托的一个或多个实例。
定义委托的语法如下:
delegate void VoidOperation(uint x);
在这个示例中,定义了一个委托VoidOperation,并指定该委托的每个实例都包含一个方法的细节,该方法带有一个uint参数,并返回void。理解委托的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所代表的方法的全部细节。
提示:
理解委托的一种好方式是把委托的作用当作是给方法签名指定名称。
假定要定义一个委托TwoLongsOp ,该委托代表的函数有两个long型参数,返回类型为double型,可以编写如下代码:
delegate double TwoLongsOp(long first, long second);
或者定义一个委托,它代表的方法不带参数,返回一个string型的值,则可以编写如下代码:
delegate string GetAString();
其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate。因为定义委托基本上是定义一个新类,所以可以在定义类的任何地方定义委托,既可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。根据定义的可见性,可以在委托定义上添加一般的访问修饰符:public、 private和 protected等:
public delegate string GetAString();
注意:
实际上,“定义一个委托”是指“定义一个新类”。委托实现为派生于基类System.MulticastDelegate的类,System.MulticastDelegate又派生于基类System.Delegate。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());
   // With firstStringMethod initialized to x.ToString(),
   // the above statement is equivalent to saying
   // Console.WriteLine("String is" + x.ToString());
在这段代码中,实例化了类型为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("$.", 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 GetCurrencyUnit()
     
         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,执行一个方法,按照升序排列一个对象数组,这个类没有委托是很难编写出来的。
参考技术A 第一步:定义委托并定义该委托对象
public delegate void DoubleClickEventHandler(object sender, 这里可以用自定义的类对象,也就是你需要传值的对象或者方法 e);
//双击ListView事件委托
public event DoubleClickEventHandler OnDoubleClick;
第二步:调用
OnDoubleClick(this, new 你刚定义的类对象);
参考技术B 先定义委托类型A,然后实力化这个委托类型的对象B,然后用B绑定一个方法,当然实力化时也可以直接写上这个方法,然后这个方法内就可以写你要写的东西了,他就是事件,另外你还要写一个自定义的事件参数类用来传值 参考技术C 1)定义委托类型,和事件
public delegate void StatusChangedDelegate();
public event StatusChangedDelegate StatusChanged;
2) 类内部触发该事件,
public void Do()

if (this.StatusChanged != null)

this.StatusChanged();


3)类的使用者注册该事件
Foo foo = new Foo();
foo.StatusChanged += new Foo.StatusChangedDelegate(foo_StatusChanged);

下面是个简单的例子,能帮到你最好了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpTest

class Program

static void Main(string[] args)

Foo foo = new Foo();
foo.StatusChanged += new Foo.StatusChangedDelegate(foo_StatusChanged);

foo.Do();


static void foo_StatusChanged()

Console.WriteLine("test event fire.");



class Foo

public delegate void StatusChangedDelegate();

public event StatusChangedDelegate StatusChanged;

public void Do()

if (this.StatusChanged != null)

this.StatusChanged();



参考技术D 参考这篇文章,有代码下载:

C#委托(Delegate)事件(Event)应用详解 (原)
http://www.csframework.com/archive/2/arc-2-20110617-1633.htm

JS 中通过对象关联实现『继承』

JS 中继承其实是种委托,而不是传统面向对象中的复制父类到子类,只是通过原型链将要做的事委托给父类。

下面介绍通过对象关联来实现『继承』的方法:

Foo = {
    // 需要提供一个 init 方法来初始化参数,而不能通过构造函数来初始化参数了
    init: function(who) {
        this.me = who;
    },
    identify: function() {
        return "I am " + this.me;
    }
};
Bar = Object.create(Foo);  // 通过 Object.create() 实现对象的关联
Bar.speak = function() {
    alert( "Hello, " + this.identify() + "." );
};
var b1 = Object.create(Bar);  // 同样通过 Object.create() 创建需要使用的对象
b1.init("b1");  // 通过 init 方法初始化成员属性
var b2 = Object.create(Bar);
b2.init("b2");
b1.speak();
b2.speak();

我们使用 Object.create() 来关联两个对象,从而实现了『继承』(委托)。

这比传统的通过构造函数实现类和继承更简洁。

其实通过 Object.create() 的方式就是修改对象的 __proto__ 来实现继承,只是直接修改 __proto__ 是不可取的,这个属性毕竟是私有的,不标准的,所以才有了 Object.create() 这个方法。

*注:Bar 使用 Object.create() 进行关联,所以要添加自己的成员只能一个个通过 Bar.xxx 进行添加,这样可能会比较麻烦。所以,可以先通过对象字面量的方式 Bar = { ... } 完成 Bar 的操作,再通过 ES6 提供的 Object.setPrototypeOf(Bar, Foo) 实现关联。

以上是关于C#中通过委托来调用对象方法的基本过程的主要内容,如果未能解决你的问题,请参考以下文章

CLR via C# 笔记 -- 委托(17)

JS 中通过对象关联实现『继承』

事件委托 EventHandler

C#编程之委托与事件四

Java中通过method对象来调用方法

在 C# 中通过引用或值传递对象