接口和抽象类保护级别的方法
本文关键字:方法 保护 抽象类 接口 | 更新日期: 2023-09-27 18:03:16
我遇到了一段代码,我不太确定为什么它能工作,或者为什么你想这样做。如果有人能帮我拆掉它,我会很高兴的。我确实很了解面向对象的概念,我只是以前没有见过这种技术。由于
示例如下:
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>();
}
}
如果你说的是这行代码:
IEnumerable<object> IInterface.DoSomething()
这叫做显式接口实现。
强制消费者只能通过接口访问这个方法,而不是直接给你的类。
上面的方法不是私有的,只是没有在代码中显式地设置为public。事实上,通过显式接口实现,您甚至不能使用访问修饰符。
采用这种方法的原因之一是强制更好的编码实践。如果你是这个类的开发者,你知道它只能通过接口访问,这就是强制实现的方法。
在c#中,通过使用一个除了调用受保护的虚方法之外什么都不做的密封方法显式地实现一个接口,这使得派生类在处理接口时具有很大的灵活性;该方法的名称应该是,而不是接口方法的名称(在上面的例子中,它可能是DoSomething_Prot)。显式接口实现使得派生类的重新实现不可能链接到基类实现,但如果基类实现所做的唯一事情是链接到受保护的虚拟或抽象方法,则派生类不需要重新实现接口。此外,即使派生类有意或由于协方差的原因重新实现接口,它仍然能够使用基类中的protected方法调用基类实现的"核心"。
将接口实现的所有代码放在隐式实现接口的public virtual方法中比将代码放在显式实现中要好,因为派生类代码通常可以链接到private成员。但是,这种方法要求所有派生类都使用相同的签名公开实现该方法。虽然这似乎是人们自然期望的,但并不总是如此。例如,在上面的示例中,派生类可能希望其DoSomething
方法返回IEnumerable<object>
以外的类型(例如,它可能返回IList<Kangaroo>
)。实现接口的方法仍然必须返回精确的类型IList<Kangaroo>
,但是知道它正在处理派生类型的代码可以使用返回类型作为IList<Kangaroo>
,而不需要类型转换。如果该方法的实际代码位于名为DoSomething_Prot()
的方法中,则派生类既可以覆盖DoSomething_Prot
,也可以声明new public IList<Kangaroo> DoSomething()
。如果基类方法被称为DoSomething()
,则派生类将无法重写它并定义一个具有不同返回类型的新方法。
在我的脑海中,我想到了一个实际用途的麻烦,但这完成的一件事是,MyBase
类型的对象或其子类没有public
或internal
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()
方法的行为。
这是一种实现方法的方法,当MyBase
s作为MyBase
s工作时不能直接调用该方法,但当它们被视为IInterfaces
时可以使用该方法。没有什么可以阻止某人这样做:((IInterface)a).DoSomething();
,但似乎隐藏是出于语义原因。
我认为这是这里描述的模板模式的实现。通常,您会看到模板模式与策略模式一起使用。在您的特定示例中,IInterface
的用户可以调用DoSomething
方法,而不考虑具体子类如何实现该方法。
这种OO编程允许您利用相当多的其他模式,例如用于创建实现IInterface
的MyBase
的具体子类的AbstractFactory。
需要注意的重要一点是,这两个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
}
}
,但这将允许您在声明为MyClass
或MyBase
的变量上调用DoSomething
,而您可能不希望它们这样做。