CLR via C#学习笔记-第八章-分部方法

8.7 分部方法

重写基类的虚方法

使用继承基类让子类重写基类虚方法的做法存在很多问题,如下所示代码。

//工具生成的代码,存储在某个代码文件中
internal class Base
{
    private String m_name;    protected virtual void OnNameChanging(String value){}
    public String Name
    {
        get{return m_name;}
        set{
            OnNameChanging(value.ToUpper());
            m_name=value;
        }
    }
}
//开发人员生成的代码。存储在另一个源代码文件中
internal class Derived:Base
{
    protected override void OnNameChanging(string value)
    {
        if(String.IsNullOrEmpty(value))
            throw new ArgumentNullException("value");
    }
}

1.类型必须是非密封的,也不能用于值类型,因为值类型是隐式密封的。此外不能用于静态方法,因为静态方法不能重写。

2.效率问题。定义一个类只为了重写一个方法,会浪费少量系统资源。即使不想重写某个方法,基类代码仍需调用一个什么都不做直接就返回的虚方法。

分布方法的实现

利用C#的分部方法就可以解决以上问题的同时覆盖类的行为。

//工具生成的代码,存储在某个代码文件中
internal sealed partial class Base
{
    private String m_name;
    partial virtual void OnNameChanging(String value){}
    public String Name
    {
        get{return m_name;}
        set{
            OnNameChanging(value.ToUpper());
            m_name=value;
        }
    }
}
//开发人员生成的代码。存储在另一个源代码文件中
internal sealed partial class Base
{
    partial void OnNameChanging(string value)
    {
        if(String.IsNullOrEmpty(value))
            throw new ArgumentNullException("value");
    }
}

1.类现在密封,事实上类可以是静态类甚至可以是值类型。

2.详细介绍partial关键字见第六章6.5节。

好处是,可以重新运行工具,在新的源代码文件中生成新的代码,但你自己的代码是存储在一个单独的文件中,不会受到影响。

性能提升

此外,分部方法还提供了另一个巨大的提升。如果不想修改工具生成的类型的行为,那么根本不需要提供自己的源代码文件。

如果只是对工具进行编译,编译器会改变生成的IL代码和元数据,使工具生成的代码变成这样。

//如果没有分布方法的实现
//工具生成的代码在逻辑上等价于以下代码
internal class Base
{
    private String m_name;
    public String Name
    {
        get{return m_name;}
        set{
            OnNameChanging(value.ToUpper());
            m_name=value;
        }
    }
}

也就是说没有实现分部方法,编译器不会生产任何代表分部方法的元数据、IL指令。

规则和原则

1.他们只能在分部类或者结构声明。

2.分部方法返回的始终是void,任何参数都不能用out修饰符来标记。

3.分部方法的声明和实现必须具有完全一致的签名。

4.分部方法总是被视为private方法。但C#编译器禁止在分布方法声明之前天机private关键字

原文地址:https://www.cnblogs.com/errornull/p/9782947.html