如果我给你任何实现的对象IDoStuffInterface
,那么你希望能够以任何实现的对象DoStuff
作为参数调用它的方法,对吗?但是,如果您想要什么是可能的,那么您可以以某种方式(作为界面用户不可见)仅使用 a调用,但不能使用任何其他实现. 因此,您想要的实际上是不可能的(也不是所希望的,因为它违反了Liskov Substitution Principle)。IMarkerInterface
DoStuff
ConcreteObject
IMarkerInterface
但是,您可以编写一个显式的接口成员实现来实现接口的DoStuff(IMarkerInterface)
方法,同时DoStuff(ConcreteObject)
在它旁边提供一个普通的方法实现。接口的任何用户都只能看到并能够调用该DoStuff(IMarkerInterface)
方法,但任何用户ConcreteDoStuff
只能直接调用该DoStuff(ConcreteObject)
方法。如果用户无论如何都想调用接口方法,则必须先将对象强制转换为IDoStuffInterface
。
public class ConcreteDoStuff : IDoStuffInterface
{
// Explicit interface member implementation:
// This method is not directly visible as a member of the class.
void IDoStuffInterface.DoStuff(IMarkerInterface obj)
{
// Do something with 'obj', or throw an exception when
// it has the wrong type. Delegate the call to the
// other DoStuff method if you wish.
}
// Normal method, technically not related to the interface method:
public void DoStuff(ConcreteObject c)
{
// Do your thing.
}
}
编辑:
有趣的解决方法!你认为这是一种普遍的做法吗?或者解决方法更像是要避免的“黑客”?
显式实现接口的技术是众所周知的、很好理解的并且非常普遍。它不被认为是hack,也不必避免。在极少数情况下,甚至需要一个类实现两个接口,这两个接口都定义了一个同名的成员,但您想赋予它们不同的行为。
但是,在您限制允许的输入值或操作的所有情况下,您都违反了 Liskov 替换原则 (LSP)。在我的示例中,您会将IMarkerInterface obj
参数限制为ConcreteObject
对象。其他示例包括: a在添加对象Collection<T>
时引发异常null
;IComparable.CompareTo
当参数类型错误时抛出错误的实现;或在调用其方法ReadOnlyCollection
时引发异常的a。Add
虽然不应该违反 LSP(因此代码变得更加(重)可用和可测试),但它经常被违反,即使在 .NET Framework 本身中也是如此。在某些情况下不违反它可能会很麻烦,导致代码难以阅读,甚至可能是不可能的(例如,由于.NET Framework 的类和接口的限制)。
正如我所说,相同的“解决方法”适用于IComparable
. 例如,要实现一个只能与相同类型的其他对象进行比较的类:
public class BeanBag : IComparable, IComparable<BeanBag>
{
private int beanCount;
// Explicit interface member implementation:
int IComparable.CompareTo(object other)
{
if (!(other is BeanBag))
throw new ArgumentException("Wrong type!");
// Calls the normal CompareTo() method.
return CompareTo((BeanBag)other);
}
// Normal CompareTo method:
public int CompareTo(BeanBag other)
{
if (other == null) return 1;
return this.beanCount.CompareTo(other.beanCount);
}
}