惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Schneier on Security
Know Your Adversary
Know Your Adversary
Security Latest
Security Latest
Spread Privacy
Spread Privacy
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
N
News | PayPal Newsroom
A
Arctic Wolf
NISL@THU
NISL@THU
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News: Ask HN
Hacker News: Ask HN
P
Palo Alto Networks Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏
L
Lohrmann on Cybersecurity
Last Week in AI
Last Week in AI
T
Threatpost
The Last Watchdog
The Last Watchdog
博客园_首页
C
Cybersecurity and Infrastructure Security Agency CISA
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Engineering at Meta
Engineering at Meta
爱范儿
爱范儿
aimingoo的专栏
aimingoo的专栏
S
Security Affairs
P
Privacy & Cybersecurity Law Blog
B
Blog RSS Feed
AWS News Blog
AWS News Blog
P
Proofpoint News Feed
雷峰网
雷峰网
T
Tenable Blog
Schneier on Security
Schneier on Security
H
Heimdal Security Blog
V2EX - 技术
V2EX - 技术
V
V2EX
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
Latest news
Latest news
Help Net Security
Help Net Security
Jina AI
Jina AI
Stack Overflow Blog
Stack Overflow Blog
The Cloudflare Blog
V
Vulnerabilities – Threatpost
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

博客园 - Easy Company

如何取得显示实现方法的MethodInfo SQL Server 2008中许多兼容性上的问题 Mock 对象何时使用? ThreadPool 在.Net 2.0 SP1中的部分变化可能会让你的程序停止工作 目前不能使用SQL Server 2008 CTP February 2008存储Team Foundation Server 2008的数据 Javascript操作在各浏览器下的性能比较 WCF Web 编程模型资源 代码行数引起的思考 在按钮点击后禁用它直到操作完成 - Easy Company - 博客园 ASP.NET 2.0中使用强类型访问PreviousPage属性页的控件 Silverlight 与 Microsoft ASP.NET Futures (July 2007) 更新 VS 2008 和.NET 3.5 Beta 2 安装注意事项 CIL(Common Intermediate Language)指令集 刚刚下载了 Visual Studio 2005 Service Pack 1 (SP1) 使用 Facade 设计模式管理 ASP.Net Session 变量 .Net 中的日志 使用 Membership 时获取用户的最后登录时间 How To 推荐用于 AJAX 页面的进度指示器图片
Partial Methods
Easy Company · 2007-07-12 · via 博客园 - Easy Company

在 .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 是参数的属性。由此可以看出分部方法是将会合并定义声明和实现声明中使用到的属性。

相关资料: