【问题标题】:Implementing interfaces in C# .NET在 C# .NET 中实现接口
【发布时间】:2012-11-06 09:04:09
【问题描述】:

考虑如下界面

public interface ICustomData
{
    String CustomData { set; get; }
}

根据 MSDN 文档,接口成员自动公开。

假设我现在想实现我的接口:

public class CustomDataHandler : ICustomData
{
}

这会在编译时中断,告诉我我没有实现“CustomData”

另一方面,这会起作用:

public class CustomDataHandler : ICustomData
{
    public String CustomData { set; get; }
}

我的问题是:如果接口的成员自动公开,为什么我必须在类中声明实现?如果接口声明在语法上与类声明相同,为什么编译器不能从我的接口中自动推断出来?

编辑:

我问的原因。想象一下您正在构建数据模型、实体等的场景。我可能会为这些模型编写一些接口,如下所示:

public interface IUserAccount
{
    Guid Identity { set; get; }
    String FirstName { set; get; }
    String LastName { set; get; }
    String EmailAddress { set; get; }
    String Password { set; get; }
}

public interface IUserDataEntry
{
    Guid DataIdentity { set; get; }
    String DataName { set; get; }
    String Data { set; get; }
}

这样构建模型会简单得多:

public class UserAccount : IUserAccount
{
}

public class UserDataEntry : IUserDataEntry
{
}

public class Combined : IUserAccount, IUserDataEntry
{
}

【问题讨论】:

  • 它可能可以,但这会让你编写可读性差的代码。
  • 寻找抽象类,它们可能就是你想要的。
  • @Bgi,你能解释一下它是如何导致代码可读性差的吗?我个人认为代码会更整洁,因为您可以只查看类实现的接口而不是类本身。此外,实现和契约在语法上是相同的,因此您只需要在接口中维护属性,而不是在类中。
  • @trampi,不,C# 只允许单继承,所以抽象类也不起作用!

标签: c# .net interface compilation


【解决方案1】:

接口不是用来提供实现的,它是用来定义契约的。然后,这允许构建实现它的不同实现。

【讨论】:

    【解决方案2】:

    它们可能在语法上相同,但它们的含义不同(即它们在语义上相同)。

    在接口中,语法意味着实现类必须公开这样的属性,并按照它认为合适的方式(显式或隐式)实现getset 访问器。一个接口仅仅定义了一个类必须提供的外向行为;它不提供该行为的任何实现。

    在类中,语法是“自动属性”,接口定义的属性的实现getset 访问器被隐式转换为完整的实现有一个支持领域。编译后看起来是这样的:

    public class CustomDataHandler : ICustomData
    {
        private string customData;
    
        public string CustomData
        {
            get
            {
                return customData;
            }
            set
            {
                customData = value;
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      您正在隐式实现接口。在这种情况下,类的方法签名必须与接口的方法签名匹配(包括可访问性)。确保将方法标记为 public 确保在查看类时不会出现意外,例如:

      public class CustomDataHandler : ICustomData
      {
        String CustomData {get; set}
        String PrivateCustomData {get;set;}
      }
      

      即使两个属性声明相同,CustomData 属性也将是公共的,因为它是在接口上声明的,即使声明看起来与 PrivateCustomData 的声明相同。这将是不一致的,并导致更难维护代码。

      如果你不想设置访问修饰符,你可以显式实现接口:

      public class CustomDataHandler : ICustomData
      {
          String ICustomData.CustomData { set; get; }
      }
      

      【讨论】:

        【解决方案4】:

        接口声明只是指定接口定义的行为。在您的情况下,这是一个名为 CustomData 的属性,它具有 getset(它是一个读/写属性),其类型为 string

        实现接口的类需要这样做 - 指定实现

        现在,在您的情况下,您正在使用自动实现的属性 { get; set; },它看起来与接口声明相同,但是您的 get 或 set 方法中也可以有一个支持字段和行为。

        【讨论】:

          【解决方案5】:

          这是一个示例,其中CustomData 属性在派生类中为private

          public class CustomDataHandler : ICustomData
          {
              private string CustomData { set; get; }
          
              string ICustomData.CustomData { get; set; }
          }
          

          但是这段代码可以编译,因为还有一个属性的显式实现。

          因此,public 修饰符在这种情况下并不是多余的。

          【讨论】:

            【解决方案6】:

            您必须明确地实现它,因为...您不限于以这种方式实现它。您可以使用一个字段,或者在您的方法中执行其他操作。接口只是保证该方法存在的方法契约。

            public class CustomDataHandler : ICustomData
            {
                public String CustomData
                {
                    get { return "None of your business!"; }
                    set { } // Decide to do nothing
                }
            }
            

            接口只保证这个方法存在。不是你要用它做什么。

            编辑:至于您对问题的编辑,如果您只想为一组类实现一次方法,您可能会寻求拥有一个父类而不是接口。但是,虽然可以组合接口,但不能组合父类。但是,您可以在类层次结构的不同点添加接口。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-02-27
              • 1970-01-01
              • 2012-01-22
              • 2012-02-01
              • 2018-10-11
              • 1970-01-01
              相关资源
              最近更新 更多