代码之家  ›  专栏  ›  技术社区  ›  Jonathan Parker

您认为“自动接口实现”在.NET/C#[关闭]中有用吗

  •  5
  • Jonathan Parker  · 技术社区  · 17 年前

    public class interface Person : IPerson
    {
      int ID { get; protected set; }
      string FirstName { get; set; }
      string LastName { get; set; }
      string FullName { get { return FirstName + " " + LastName; } }
    }
    

    这是:

    public class StubPerson : IPerson
    {
        int ID { get { return 0; protected set { } }
        string FirstName { get { return "Test" } set { } }
        string LastName { get { return "User" } set { } }
        string FullName { get { return FirstName + " " + LastName; } }
    }
    

    用法:

    IPerson iperson = new Person();
    

    IPerson ipersonStub = new StubPerson();
    

    或:

    IPerson ipersonMock = mocks.CreateMock<IPerson>();
    

    因此,实际上我们宣布 伊佩森 接口和 人 同时上课:

    public class interface Person : IPerson
    

    由于大量混乱,我认为我需要澄清提议的目的:

    interface IPerson
    {
      int ID { get; }
      string FirstName { get; set; }
      string LastName { get; set; }
      string FullName { get; }
    }
    

    除此之外:

    public class Person : IPerson
    {
      int ID { get; protected set; }
      string FirstName { get; set; }
      string LastName { get; set; }
      string FullName { get { return FirstName + " " + LastName; } }
    }
    

    我根本没有提议任何语义上的改变。

    9 回复  |  直到 17 年前
        1
  •  11
  •   Rex M    17 年前

    让我看看我是否理解你的问题:

    interface IPerson
    {
        string Name {get;set;}
        int ID {get;set;}
    }
    

    实现该接口的类将继承其属性,而无需重新声明:

    class Person : IPerson { } 
    //person now has properties Name and ID
    

    您不能这样做的原因是,即使接口代码和类代码的文本非常相似,它们 刻薄 不同的事情。接口只是说“实现者将有一个带有getter和setter的字符串名”。它是这样一个类:“当调用getter for name时返回private字段。”即使您使用auto属性快捷方式让编译器实现该逻辑,它仍然是 ,属于该类。只是因为:

    string Name {get;set;}
    

    看

    编译器实现任意逻辑来为您实现契约,而不是在编译时抱怨您没有实现它们,这将是非常危险的。它可能会引入很难追踪的bug。让编译器在没有定义行为的情况下返回默认行为是一个非常非常糟糕的主意。

        2
  •  4
  •   Jon Skeet    17 年前

    我考虑 the same sort of thing a while ago ,特别是在您只有一个接口的生产实现,但希望模拟它进行测试的情况下使用。现在它有点像以前的.c/.h文件。

    最后,我怀疑它的好处被语言中额外的复杂性以及随后阅读代码所抵消。不过,我仍然有兴趣看到它得到更彻底的探索。即便如此,在我的优先级列表中还有其他更高的事情——对不变性的更好支持排在首位:)

        3
  •  3
  •   Daniel Earwicker    17 年前

        4
  •  2
  •   Quintin Robinson    17 年前

    定义你的类。。。

    public class Person
    {
      public int ID { get; protected set; }
      public string FirstName { get; set; }
      public string LastName { get; set; }
      public string FullName { get { return FirstName + " " + LastName; } }
    }
    

    然后右键单击,选择重构->提取接口。

    这将创建一个单独的文件,其中包含类定义的接口,然后您可以相应地塑造接口和实现类。

    interface IPerson
    {
        string FirstName { get; set; }
        string FullName { get; }
        int ID { get; }
        string LastName { get; set; }
    }
    
        5
  •  1
  •   Andrew Hare    17 年前

    我想我没有抓住要点——通过将类和接口混合在一起,你能实现什么?你用这种方法解决了什么问题?

    这:

    IPerson iperson = new Person();
    

    在C#中已经是合法的。

    编辑: 澄清-鉴于以下情况,上述规范是合法的:

    interface IPerson { }
    
    class Person : IPerson { }
    
        6
  •  1
  •   Sekhat    17 年前

        7
  •  0
  •   Robin Clowers    17 年前

    ReSharper ,再也不用担心了。

        8
  •  0
  •   Jon Limjap    17 年前

    Resharper可以提供此功能,例如。,

    1. pulling members up 到IPerson接口。

    使现代化

    无论如何,让我们先来阐述接口,引用您在问题中提供的代码:

    public class interface Person : IPerson
    {
        int ID { get; protected set; }
        string FirstName { get; set; }
        string LastName { get; set; }
        string FullName { get { return FirstName + " " + LastName; } }
    }
    

    您必须理解接口不是抽象类。接口仅仅是 合同

    另一方面,抽象类可以包含可以继承和重写的功能片段。

    • 您不能在接口(公共、私有、受保护、内部)上声明范围约束,因为这是一个实现细节
    • 您无法声明默认实现(例如 FullName

    在我看来,您真正想要的是一个抽象类,例如。,

    public abstract class BasePerson
    {
        public abstract int ID { get; protected set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public virtual string FullName { get { return FirstName + " " + LastName; } } 
    }
    

    更新2

    好吧,我想我已经了解了你想要发生的事情,所以你想要的是能够写下:

    public interface IPerson
    {
        int ID { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
        string FullName { get; }
    }
    

    public class Person : IPerson
    {
        public int ID { get; protected set; }
        public string FullName { get { return FirstName + " " + LastName; } } 
    }
    

    无需指定FirstName和LastName属性。

    我们需要解决的第一个问题是,接口在其实现中不允许访问定界符:将发生的情况是,属性将继承默认的访问定界符,它是私有的。

    string FirstName { get; set; } public string FirstName { get; set; }

    • 在类中,属性定义将指示CLR创建一个匿名对象,该对象将保存所述属性的值。

    对于程序员来说,这是一个微妙的差别,对于编译器来说,这是一个截然不同的世界。

    最后,当您指定要实现一个接口时,VisualStudio会执行同步魔术,自动为您创建这些属性存根。

        9
  •  0
  •   Jordão    15 年前

    here ,一个角色。这就像是一个带有代码的接口。您的示例可以这样编码:

    public role RPerson { 
      int ID { get; protected set; } 
      string FirstName { get; set; } 
      string LastName { get; set; } 
      string FullName { get { return FirstName + " " + LastName; } } 
    } 
    
    public class Person : RPerson { }
    
    public class StubPerson : RPerson { 
        int ID { get { return 0; protected set { } } 
        string FirstName { get { return "Test" } set { } } 
        string LastName { get { return "User" } set { } } 
        string FullName { get { return FirstName + " " + LastName; } } 
    } 
    
    // ...
    
    RPerson rperson = new Person(); 
    
    RPerson rpersonStub = new StubPerson();