081106(转载)c# 2.0之 partial

常常看见大家在热火朝天的讨论 VS.Net Whidbey 和 .Net FrameWork 2.0 的新功能,而我却现在还在这边比对了半天才敢确定我的“Whidbey”这七个字母没有敲错。:(

今天刚刚在 VPC 中装上了 VS.Net 2005 Community Technology Preview,决心好好体验一把 .Net Framework 2.0 和 C# 2.0 的犀利之处。

打开新的 VS.Net,新建一个 WinForm Application,马上就发现了不同之处:“窗体设计器生成的代码”哪里去了?InitializeComponent()那里去了?

端详片刻,才发现原来是这个 partial 关键字搞的鬼。

partial 关键字的作用是将你的 class 分为多个部分,编译器会将多个部分拼到一起去。

public partial class SampleClass
...{
public void MethodA()
...{
}
}

public partial class SampleClass
...{
public void MethodB()
...{
}
}



public class SampleClass
...{
public void MethodA()
...{
}
public void MethodB()
...{
}
}


是等价的。

我猜想这个东西出现的初衷是为了解决掉:“窗体设计器生成的代码”这个令人讨厌的 region。

对我们来说,在团队开发当中这个东西或许也会有点用处。

我 观察了一下生成的 IL 代码,使用 partial 生成的代码并没有什么特殊的标记,这说明 partial 纯粹是语言的特性,CLR 完全不知道这么个玩意的存在,这也就意味着不要指望将 partial class 编译为 assembly 或者 module 什么的再与其他的人写的 partial class 去进行拼接:它只能在编译的时候起作用。

为了考验一下编译器,我试着让某一个 partial class 不显式指定父类,发现代码仍然能够正确的通过编译,编译器会按照某一个显式指定了父类的 partial 进行编译,只有在多个 partial 指定了不同父类时才会报错。同样,如果多个 partial 指定了自相矛盾的修饰符的话,编译时也会报错的。

有意思的是,我们还可以写以下这样的代码:

public partial class Sample
...{
public partial class SampleSon
...{
public partial class SampleGrandson
...{
}
}
}
public partial class Sample
...{
public partial class SampleSon
...{
public partial class SampleGrandson
...{
}
}
}

****************************************************************************************************************

一般来说,我习惯把数据库操作部分和相应的类放在一起,比如,一个 BookCollection 类就应该自己包含操作 Book 表:


view plaincopy to clipboardprint?
using System;    
using System.Collections;    
   
public class Book    
{    
    public string BookName;    
}    
   
public class BookCollection : CollectionBase    
{    
    public void Add(Book b)    
    {    
        List.Add(b);    
        SaveToDatabase(b);    
    }    
        
    private void SaveToDatabase(Book b)    
    {    
        string sql = string.Format(    
            "Insert Into [Books] ([BookName]) Values (’{0}’)",    
            b.BookName.Replace("’", "’’"));    
        SqlConnection.CreateCommand(sql).ExecuteNonQuery();    
    }    
}  


不过,对于三层结构的程序要求来说,应该把数据库操作部分和业务逻辑部分拆分开来:


view plaincopy to clipboardprint?
using System;    
using System.Collections;    

  public class Book    
{    
    public string BookName;    
}    
   
public class BookCollection : CollectionBase    
{    
    public void Add(Book b)    
    {    
        List.Add(b);    
        BookAccess.SaveToDatabase(b);    
    }    
        
}    
   
public class BookAccess    
{    
    public static void SaveToDatabase(Book b)    
    {    
        string sql = string.Format(    
            "Insert Into [Books] ([BookName]) Values (’{0}’)",    
            b.BookName.Replace("’", "’’"));    
        SqlConnection.CreateCommand(sql).ExecuteNonQuery();    
    }    
}  
这样做的话,既有优点,也有缺点。优点是,可以把所有的和数据库相关的操作分在同一组(比如另一个DLL中),也更容易查找和修改。而缺点是, 必须把 SaveToDatabase 的访问操作符设置成 public,否则外部无法调用,无法指定由哪个类调用,而另一方面,以前的代码中的 SaveToDatabase 是 private 的,所以可以保证只有 BookCollection 才能调用 SaveToDatabase 函数,可以减少无谓的错误。
但是,在 .Net 2005 中,可以使用 partial class 使之兼具这两种方法的优点:

view plaincopy to clipboardprint?
using System;    
using System.Collections;    
   
public class Book    
{    
    public string BookName;    
}    
   
public partial class BookCollection : CollectionBase    
{    
    public void Add(Book b)    
    {    
        List.Add(b);    
        BookAccess.SaveToDatabase(b);    
    }    
        
}    
   
public partial class BookCollection    
{    
    private void SaveToDatabase(Book b)    
    {    
        string sql = string.Format(    
            "Insert Into [Books] ([BookName]) Values (’{0}’)",    
            b.BookName.Replace("’", "’’"));    
        SqlConnection.CreateCommand(sql).ExecuteNonQuery();    
    }    
}  
   不过,以前我以为 partial class 也可以分布在不同的 Assembly 中,查了 C# 的在线帮助,是这样说的:

All partial-type definitions meant to be parts of the same type must be defined in the same assembly
and the same module (.exe or .dll file). Partial definitions cannot span multiple modules.

而,VB.Net 的帮助中关于 Partial Class 的说法是这样的:

However, all the declarations must be in the same assembly and the same namespace.

所以,虽然我们可以把一个类用 partial 分成两个源文件,但是无法拆分到两个 dll 中,否则,对于这种数据访问层、业务逻辑层的拆分会更有利的。   我之所以以前认为 partial class 可以分布在不同的 Assembly 中,原因在于在 .Net 2005 中的 web 开发也是使用的 partial class,而源程序文件和 aspx 文件应该会被编译到不同的 Assembly 中,所以,在发现 partial class 不能编译到不同的 Assembly 中后,又查看了一下 web 页,结果没有发现编译出的 dll 文件!难道 .Net 2005 的 asp.net 开发需要同时发布源程序文件的么?
http://hi.baidu.com/surfcaster/blog/item/6fc429eda0defe4979f05564.html
posted @ 2008-11-06 14:47  以函  阅读(169)  评论(0编辑  收藏  举报