如果我问你,如果一个普通的类实现了一个接口方法,但是这个类的实例却访问不到这个接口的方法,这种情况你遇到过吗?有时候,你可能在使用分部方法时就会发现这么一个现象。

    C#3 中出现了 “分部方法” ,工作了好几年一直没用过,可能不咋实用,也有可能是工作中没有遇到这种场景,分部类倒是用了不少。最近看了一下,内容简单,标记一下。

    我们 分部方法 和分部类有点类似的是 也是使用的关键字 partial ,不过不同的是 部分方法 不能有访问修饰符 (像public) 或者 virtual ,abstract,override,new,sealed,extern  。

     而分部类是没有这个限制。那么你应该会想这个方法,是会像接口中定义的没法带修饰符方法一样 天生是公用的,  还是像普通类中 是私有的呢,我迫不及待的做了个代码,结局倾向了后者。

//文件1中

 public partial class People
    {
        public People(string arg)
        {
              Speak($"我被构造了,带着{arg}");
        }

        partial void Speak(string paramStr);
    }

//文件2中

 public partial class People
    {
        partial void Speak(string paramStr)
        {
            Console.WriteLine($"收到参数{params}");
        }
    }

   测试

class Test
    {
        static void Main()
        {
            People p= new People("2019到了");
            //p.Speaks("Hello");     访问不到                  
            Console.ReadKey();
        }
    }

      上面是我们的使用例子,部分方法 限制了我们的方法不能有返回值,只能是void的方法,且不能获取out参数,它必须是私有的,可以是静态的或者泛型。

      文件1中   分部方法 的申明和抽象方法相同,只提供了partial修饰符的签名而没有实现,以分号结尾。我们分析文件1中的IL代码,发现构造函数中没有任何痕迹。

      接下来,我们看下如果定义接口,然后实现的时候使用分部方法呢。

    public interface IPeople
    {
        void Speaks();
    }

//文件1

  public partial class People:IPeople
    {
        partial void Speaks();
    }

//文件2

 public partial class People : IPeople  //接口可写可不写
    {
       void IPeople.Speaks()
        {
            Console.WriteLine("哎呀,2019都来了");
        }
    }

       我们发现 实现接口需要显式实现。然后我们调用看看:

 class Test
    {
        static void Main()
        {           
            People p2 = new People();
           // p2.Speaks();  访问不到
    }

     p2访问不到实现的接口方法。当然,如果再定义一个子类,子类的实例也是访问不到的。那么怎么才能访问到呢,你一定会这么写:

 class Test
    {
        static void Main()
        {
            IPeople p1 = new People();
            p1.Speaks(); // 完全ok        
   }

      所以你总的感觉下来,这个东西限制还是蛮大的。这个特性特别适用那些自动生成代码和手动写代码一起交互场景。概况的说,C#3的分部方法让生成代码可以和手写代码以一种丰富的方式进行交互,而不会产生任何性能上的损失,可以说是C#2分部类一种自然的延续。

01-27 06:12