【问题标题】:Properties in an Interface接口中的属性
【发布时间】:2015-08-28 01:29:14
【问题描述】:

在我的界面中,我用 setter 和 getter 声明了一个属性。

public interface ITestInterface
{
   string AProperty { get; set; }
}

当我编写继承该接口的类时,为什么我需要再次定义这两个属性?

public sealed class MyClass: ITestInterface
{
   public string AProperty { get; set; }
}

【问题讨论】:

  • 我认为这里的问题是,相同的语法对于接口和类有两种不同的含义。 AProperty { get; set; } 在接口中是仅声明,在类中是自动实现的接口。
  • 如果你想为继承类提供一些类成员而不必在继承类中再次编写它们,但又想强制实现你提供的一些签名,抽象类将是一个不错的选择.使用接口,您只需提供签名并强制实现该接口的任何类都具有这些“原型”的实现。

标签: c# .net oop properties interface


【解决方案1】:

我认为这里的混淆来自这样一个事实,即自动属性(只是 get 和或 set 声明)在接口和实现中看起来相同。接口只是一个类必须提供的声明(合同)才能被视为接口的实现者。如果您考虑接口中的方法声明与类中的实现,会更清楚。

接口 = 要求; Class = 如何满足这些要求

public interface ITestInterface
{
   string GetAProperty();
}

public class MyClass : ITestInterface
{
    public string GetAProperty()
    {
        // Do work...
        return "Value";
    }
}

【讨论】:

    【解决方案2】:

    简答

    因为接口只包含一个类的定义,并且不能包含任何成员函数的实际实现。这是设计使然。

    长答案

    首先你必须认识到属性基本上是getset 成员函数,具有一些简化的语法。因此这里的问题是:为什么接口定义不能包含成员函数的实现?

    嗯,在某些语言中(最著名的是:C++)你可以。

    如果你有一个继承链,那基本上是通过查找表来解决的。假设您有成员函数 1,那么在继承链中的所有类中,都有一个包含指向函数 1 的指针的表。一旦调用成员函数,该调用基本上会从属于该类型的表中获取第一个条目你的对象,并称之为。这个东西叫做vtable(更多细节请看here)。

    现在,在 C++ 中,VTable 对开发人员来说是非常透明的:每个类基本上都有一个 vtable,并且没有真正的“接口”这样的东西。这也意味着所有类都可以具有实现和成员,例如字段。如果你有一个只有纯虚拟成员的类(例如没有实现的函数),那么你就有了相当于 C++ 的“接口”。

    在软件工程中,这些类通常被称为“接口”类,因为它们只包含对正在发生的事情的定义,而不是实际的实现。接口具有很好的特性,它们描述功能而不实际进入细节,因此可以在代码中放置“边界”。这有很多用例,包括(RPC)通信、很多设计模式等等。

    在 C++ 中,一个类可以派生自多个类(多重继承),有和没有实现。此外,由于接口实际上更像是“抽象”类而不是 C# 中的“接口”,这意味着您也可以在那里添加功能。因此,前面描述的 vtable 包含指向所有基类中的函数的指针。

    当您开始向接口类添加功能时,问题就开始了。对于初学者,假设你有这样的东西(我会用某种 C# 来做):

    interface A { Foo(); } // basically an interface.
    interface B : A { Foo(); } // another interface
    class B : A { void Foo() {...} } // implementation of Foo, inherits A
    class D : B,C { } // inherits both B, C (and A via both B and C).
    

    我们感兴趣的是,如果您在课堂上调用Foo 会发生什么D。为此,我们必须为类D 构造一个vtable。基本上这个 vtable 应该是这样的:

    Foo() -> C::Foo()
    

    这意味着如果你构造一个D的对象,并调用Foo,你最终会调用Foo类型C的实现:

    var tmp = new D();
    tmp.Foo(); // calls C::Foo()
    

    当我们将 B 的定义更改为如下内容时,它变得更加困难:

    class B : A { void Foo() {...} } // changed into an implementation
    

    再一次,我们尝试为D 类构建vtable,但我们最终遇到了一个问题:

    Foo() -> C::Foo() or B::Foo()???
    

    我们在这里面临的问题是:调用该成员时,我们将使用Foo 的什么实现?另外,我们要调用什么构造函数?那么毁灭令呢?在 C++ 中有一种解决方法,称为 虚拟继承

    在设计 .NET 和 C# 语言时,他们考虑了过去的多重继承经验以及虚拟继承的含义,并认为这不仅是一件难以实现的事情,而且充其量也让开发人员感到非常困惑。如您所见,只要添加接口,这些问题就不存在了。

    所以,这就是为什么你的界面中不能有属性(或方法)。

    【讨论】:

      【解决方案3】:

      正如其他人所说,接口只是您的方法和属性签名的容器。它需要实现,但这个实现签名将与接口中使用的签名完全匹配。它还保证所有这些成员都可以在类实例中访问,因为它们默认是公共属性,并且没有实现程序将根本无法编译。

      假设你有接口:

      public interface ITestInterface
      {
          string AProperty { get; }
      }
      

      以及实现它的类:

      class MyClass : ITestInterface
      {
         public string AProperty { get { if (DateTime.Today.Day > 7) return "First week of month has past"; return "First week of month is on"; } }
      }
      

      无法使用自动实现的属性,也无法在此类中添加 setter,因为接口属性缺少 set 访问器,并且自动实现的属性要求接口包含自动实现的属性签名 ({ get; set;})。因此,在您的示例界面中,只需声明属性即可。

      只要知道类继承了哪些接口,您就知道那里有哪些成员,如果您只想使用(或允许用户使用)其中一些方法(但不允许更改任何内容),您总是可以向上转换您的类实例到这些接口类型之一并将其作为参数传递。

      【讨论】:

        【解决方案4】:

        你的接口定义只告诉有一个带有getter和setter的属性,而不是它是如何实现的。您可以使用自动实现的属性,但不是必须的。

        按照接口,这将是一个有效的实现:

        public sealed class MyClass: ITestInterface
        {
            public string APROPERTY
            {
                get { return someField + " hello"; }
                set { someOtherField = value; }
            }
        }
        

        在接口定义中,string AProperty { get; set; } 是属性的声明,而在类中,则表示该属性是自动实现的

        【讨论】:

          【解决方案5】:

          因为您不是从接口继承,所以您正在实现该接口。 (尽管它们共享相同的语法:

          public class MyClass : IMyInterface { ... } //interface implementing
          public class MyClass : MyBaseClass { ... } //inheriting from a class
          

          假设您正在继承一个糖果盒(不是从您的祖先继承,以编程方式),它(不完全)就像您将糖果盒放在另一个盒子中,现在是外盒(派生类,继承的) 继承自糖果盒并拥有糖果盒所拥有的所有东西,但是如果您想自己实现(制作)糖果盒,则必须构建一个盒子并在其中放入一些糖果。这就是接口的工作方式。

          【讨论】:

            【解决方案6】:

            接口包含属性签名而不是实际定义。您实际上是在请求任何实现 ITestInterface 的类来实现 AProperty 的 get 和 set。请参阅thisthis 了解更多详情。

            【讨论】:

              【解决方案7】:

              我认为这里的问题是,相同的语法对于接口和类有两种不同的含义。 AProperty { get; set; } 在接口中是仅声明,在类中是自动实现的接口。

              所以该术语取决于上下文。

              public interface ITestInterface
              {
                  string AProperty { get; set; }
              }
              

              声明属性,但无法实现。

              public sealed class MyClass: ITestInterface
              {
                  public string AProperty { get; set; }
              }
              

              实现接口,其中属性自动实现(仅适用于类)。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-09-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-10-31
                • 2019-04-20
                • 2018-01-22
                • 2013-01-15
                相关资源
                最近更新 更多