【问题标题】:Interface and abstract class protection level methods接口和抽象类保护级别方法
【发布时间】:2013-02-26 21:34:58
【问题描述】:

我遇到了一些代码,但不太确定它为什么会起作用,或者您为什么要这样做。如果有人能为我拆掉它,我会很高兴的。我确实很了解 OOP 概念,我以前从未见过这种技术。谢谢

示例如下:

public interface IInterface
{
    IEnumerable<object> DoSomething();
}

public abstract class MyBase : IInterface
{
    protected MyBase()
    {
    }

    IEnumerable<object> IInterface.DoSomething()
    {
        return DoSomething();
    }

    protected virtual IEnumerable<object> DoSomething()
    {
        return new List<object>();
    }
}

public class MyClass : MyBase
{
    internal MyClass() : base() {}

    protected override IEnumerable<object> DoSomething()
    {
          return new List<object>();
    }
}

【问题讨论】:

  • 不清楚您对示例的哪个方面感到困惑。
  • 我猜这是带有受保护的隐式实现的显式接口实现(如果是这样的话 - 我会说隐式接口实现是公共的)。
  • 我很抱歉。让我困惑的部分是在我看来是返回虚拟 DoSomething 的 IInterface.DoSomething 的私有实现。我还注意到了 IInterface。它是编译所必需的。
  • 这没有意义。看起来有人试图从基类中隐藏DoSomething

标签: c# oop class interface protected


【解决方案1】:

如果你说的是这行代码:

IEnumerable<object> IInterface.DoSomething()

那叫explicit interface implementation

这迫使消费者只能通过接口访问此方法, 而不是直接到你的班级。

上述方法不是私有的,只是没有在代码中明确设置为公共。事实上,通过显式接口实现,您甚至不能使用访问修饰符。

采用这种方法的原因之一是强制执行更好的编码实践。如果您是此类的开发人员,并且您知道它只能通过接口访问,那么这就是强制发生这种情况的方法。

【讨论】:

  • 我知道显式接口imp,并且我知道当您使用多个碰巧具有相同命名方法的接口时,它会派上用场。我仍然不确定程序员为什么这样做以及它带来了什么好处。
  • 定义了两个接口时,不仅仅使用一个接口;它是关于强制一个类通过接口而不是直接使用类本身来使用(即使只涉及一个接口)。我的回答说明了这样做的原因。
  • 在 C# 中,您不能修改显式接口实现 - 它始终是私有的。在 VB.NET 中,我相信您可以根据需要进行显式实现。就个人而言,我更喜欢 C# 方式。
  • @JoeEnos 这不是private。也不是public,或internal,或......任何东西。您不能指定访问修饰符,因为 * 没有任何意义。您通过接口访问它,因此可访问性就是接口本身的可访问性,仅此而已。你不可能指定private,因为如果你这样做了,那么你就不会满足接口的合同。如果是public,您可能会将方法暴露在比接口更大的范围内。最后,允许访问修饰符充其量是多余的,最坏的情况是违反接口契约。
  • 查看Skeet's answer and comments - 一切都取决于您的观点。但是在 VB 中,它可以是显式私有的或公共的(或我认为的任何其他):Public Sub Go() Implements ISomething.Go 是有效的,并且允许您通过接口访问Go - Private Sub Foo() Implements ISomething.Foo 也是有效的,并且行为相同像 C# 一样,只允许通过接口访问。
【解决方案2】:

在 C# 中,通过使用密封方法显式实现接口,该方法除了调用受保护的虚拟方法之外什么都不做,这允许派生类在他们想要对接口做什么方面具有很大的灵活性;应该为方法指定一个名称​​other,而不是接口方法的名称(在上面的示例中,它可能是 DoSomething_Prot)。显式接口实现使得派生类的重新实现不可能链接到基类实现,但是如果基类实现唯一要做的就是链接到受保护的虚拟或抽象方法,则不需要派生类类来重新实现接口。此外,即使派生类有意或由于协变而重新实现接口,它仍然能够使用基类中的受保护方法调用基类实现的“胆量”。

将接口实现的所有代码放在隐式实现接口的公共虚拟方法中比将代码放在显式实现中要好,因为派生类代码通常可以链接到私有成员。然而,这种方法要求所有派生类公开实现具有相同签名的方法。尽管这似乎是人们自然期望的结果,但并非总是如此。例如,在上面的示例中,派生类可能希望其DoSomething 方法返回IEnumerable&lt;object&gt; 以外的类型(例如,它可能返回IList&lt;Kangaroo&gt;)。实现接口的方法仍然必须返回精确类型IList&lt;Kangaroo&gt;,但是知道它正在处理派生类型的代码可以将返回类型用作IList&lt;Kangaroo&gt;,而无需进行类型转换。如果该方法的实际代码位于名为DoSomething_Prot() 的方法中,则派生类既可以覆盖DoSomething_Prot,又可以声明new public IList&lt;Kangaroo&gt; DoSomething()。如果基类方法被称为DoSomething(),那么派生类将无法同时覆盖它并定义具有不同返回类型的新方法。

【讨论】:

    【解决方案3】:

    需要注意的重要一点是,这两个DoSomething 方法彼此无关——它们只是碰巧同名。

    基本上,您只是获得了一个公开DoSomething 方法的普通接口,因此拥有IInterface 对象的调用者可以调用它。然后它将依次将调用传递给受保护的DoSomething 方法的适当实现,该方法可以来自基类或派生类。

    像这样的显式实现会迫使您通过契约而不是实现来编码 - 并没有真正提供任何实际保护,只是让您在声明变量时更难意外使用错误类型。他们本来可以轻松做到的:

    public abstract class MyBase : IInterface {
        public virtual IEnumerable<object> DoSomething() {
           // blah
        }
    }
    
    public class MyClass : MyBase {
        public override IEnumerable<object> DoSomething() {
            // blah
        }
    }
    

    但这会让您在声明为MyClassMyBase 的变量上调用DoSomething,您可能不希望他们这样做。

    【讨论】:

    • 这个解释让我更清楚了。您是否也同意 nattyddubbs 这看起来像模板模式?我需要对这种模式进行一些阅读。
    • 这似乎是正确的 - 以前从未将其称为模板模式,但这是非常简单的基于继承的 OOP - 子类中的基类和重写方法,以使它们按照您的意愿行事。
    • 想通过投票给你支持,但我的声望还不够高。再次感谢您指出命名块!
    【解决方案4】:

    我对此的看法是,它是here 中描述的模板模式的实现。通常,您会看到与 strategy 模式一起使用的模板模式。在您的特定示例中,IInterface 的用户可以调用DoSomething 方法而不考虑具体子类如何实现该方法。

    这种 OO 编程允许您利用很多其他模式,例如 AbstractFactory 来创建实现 IInterfaceMyBase 的具体子类。

    【讨论】:

      【解决方案5】:

      在我的脑海中,我很难想到它的实际用途,但是这样做的一件事是 MyBase 类型的对象或其子类没有 public 或 @987654323 @ly 可见DoSomething() 方法:

      MyClass a = new MyClass();
      a.DoSomething();  // Compile error
      

      但是当对象用作IInterface时,DoSomething()方法是可见的:

      void AMethod(IInterface i)
      {
          i.DoSomething(); // compiles just fine
      }
      
      void AnotherMethod(MyBase a)
      {
          AMethod(a); // as does this
      }
      

      制作非显式版本protected virtual 允许子类覆盖DoSomething() 方法的行为。

      这是一种实现方法的方法,在将MyBases 用作MyBases 时不能直接调用,但可以在将它们视为IInterfaces 时使用。没有什么可以阻止某人这样做:((IInterface)a).DoSomething(); 但似乎隐藏是出于语义原因。

      【讨论】:

      • 有关使用的更多信息,在同一程序集中有一个工厂类,它创建并返回 MyClass。使用该 MyClass 的类也在同一个程序集中,它调用方法没有问题。示例 var myClass = SomeFactory.GetMyClass(); myClass.DoSomething()
      • 这可能是因为GetMyClass() 返回一个接口,而不是具体的 myBase 或 myClass。
      • 是的,工厂方法返回一个接口。
      • 这可以解释为什么该方法被调用而没有问题。
      • 我认为我的回答为这个构造提供了一个目的,尽管受保护的DoSomething() 方法应该具有与接口方法不同的名称或参数签名。
      猜你喜欢
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-02
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多