Partial Methods

在 .net framework 3.5 中增加了一个新的功能叫做分部方法(partial method,因在.net framework 2.0中partial class在msdn中译做分部类型,所以此处暂称为分部方法)。分部方法是一些方法,它使轻量级的事件处理成为可行。它被包含在VS 2008 Beta2中的 VB 和 C# 中,本文将以C#来说明,下面是一个声明示例:

        partial class C
        {
            static partial void M (int i);
        }
       
在定义分部方法时,值得注意的是:
      1、分部方法必须声明在分部类型(partial class)中;
      2、分部方法使用 partial 修饰符;
      3、分部方法并不是总有方法体(body,即方法的实现);
      4、分部方法必须返回 void;
      5、分部方法可以是静态的(即使用 static 修饰符);
      6、分部方法可以包含参数(包括在参数中使用 this、ref 和 params 修饰符,不支持 out 修饰符可以使用 ref 修饰符来代替它);
      7、分部方法必须是私有方法(private)。
     
现在再看一个分部方法的例子,假设我要调用 C.M 方法
  
      partial class C
      {
          static void Main()
          {
              C.M(Calculation());
          }
      }
     
因为 C.M 没有方法体(body),所以它将在编译时(compile time)连同求值参数(the evaluation of the arguments)一起被移除。所以上面的程序等同于:

      partial class C
      {
          static void Main()
          {
          }
      }
     
从上面看,分部方法很类似条件方法(预编译符#if...#else中包含的方法),在某些时候它可以连同参数一起被编译器移除。但是分部方法比条件方法更进一步,当一个分部方法没有方法体时,那么它就不会被发行到元数据(metadata)中。

到现在为止,你可以通过上面的代码看出,C#允许用户在调用中声明方法和求值参数,并且这个方法和它的求值参数可以在类中没有定义其实现的方法体(body)。分部方法允许用户为一个已声明的方法定义一个方法体(body),因此一个方法有了声明和实现后就会被发行到元数据(metadata)中。
     
      partial class C
      {
          static partial void M (int i);    // 定义分部方法声明
          static partial void M (int i)     // 实现声明
          {
          }
      }
     
在上面的代码中,我们看到一个分部方法的声明和一个分部方法的实现有一些不同,这个不同就是方法是否包含一个方法体(body)。在一个分部类型(partial class)中不允许存在一样的定义。只允许有一个分部方法的定义声明和在一个定义声明存在时可能会有的该分部方法的实现声明。

为什么会有分部方法?

那么如何使用分部方法呢?最常见的情况是使用它们做轻量级的事件处理。比如一个工具生成的代码中可能希望在执行的时候能挂上用户自定义的代码。又如,试想一个工具为一个表示客户(customer)的类生成了如下代码:

      partial class Customer
      {
          string name;
         
          public string Name
          {
              get { return name; }
              set
              {
                  OnBeforeUpdateName();
                  OnUpdateName();
                  name = value;
                  OnAfterUpdateName();
              }
          }
         
          partial void OnBeforeUpdateName();
          partial void OnUpdateName();
          partial void OnAfterUpdateName();
      }
     
如果用户没有添加任何实现定义,那么上面的代码等同于:

      partial class Customer
      {
          string name;
         
          public string Name
          {
              get { return name; }
              set { name = value; }
          }
      }
     
可以看到没有了那些无用的指令。如果用户侦听 OnUpdateName “事件”("event",轻量级的):

      partial class Customer
      {
          partial void OnUpdateName()
          {
              DoSomething();
          }
      }
     
那么最初的定义就会等同于如下代码:

      partial class Customer
      {
          string name;
         
          public string Name
          {
              get { return name; }
              set
              {
                  OnUpdateName();
                  name = value;
              }
          }
         
          partial void OnUpdateName();
      }
     
比较分部方法与其他实现

此时,会提出一个问题:为什么不使用子类和虚方法(virtual methods)?当然这些同样可以实现,但是在调用时有一个弊病,在子类中没有对方法进行重写(override)时,方法和求值参数(the evaluation of the arguments)也要被发行。因此,在一个类似于LINQ to SQL这样的有数以千计的小事件的系统中,它允许一些非常轻量级的事件,用户只需实现那些他们使用的事件。

几个细节

思考下面的程序...

      partial class C
      {
          static void Main()
          {
              int i = 3;
              C.M(i = 5);
              Console.WriteLine(i);
          }
      }

在控制台中输出的结果是什么?3,5,...?

事实上,根据这段代码是无法判断的。如果没有分部方法 C.M 的实现声明则程序将显示 3,因为 i=5 没有被计算;但是如果有该方法的实现声明,则这个程序将显示 5。当然同样的技巧可以用在隐藏昂贵的计算上。

      partial class C
      {
          static void Main()
          {
              C.M(VeryVeryExpensiveCalculation());
          }
      }
     
如果没有实现声明,那么 VeryVeryExpensiveCalculation() 将永远都不执行。

现在看一下分部方法在属性(Attributes)上是如何工作的?

      partial class D
      {
          [W]
          [return:X]
          partial void M<[Y]T>([Z]int foo)
          {
          }
         
          [Z]
          [return:W]
          partial void M<[X]T>([Y]int foo);
      }
     
什么属性现在会标记到 M 的元数据中?W 和 Z 是 M 上的属性;X 和 W 是返回类型的属性;Y 和 X 是类型参数的属性;Z 和 Y 是参数的属性。由此可以看出分部方法是将会合并定义声明和实现声明中使用到的属性。


相关资料:

posted on 2007-07-12 16:33  Easy Company  阅读(561)  评论(0编辑  收藏  举报

导航