を実装するオブジェクトを指定すると、を実装する任意のオブジェクトを引数としてIDoStuffInterface
メソッドを呼び出すことができると期待されますよね? ただし、必要なことが可能である場合は、何らかの形で(インターフェイスのユーザーとしては見えない) でのみ呼び出すことができますが、 を実装する他のオブジェクトは呼び出すことができません。したがって、あなたが望むことは実際には不可能です ( Liskov Substitution Principleに違反するため、望ましくありません)。DoStuff
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.
}
}
編集:
興味深い回避策!これは常識だと思いますか?それとも回避策は回避すべき「ハック」ですか?
インターフェイスを明示的に実装する手法は、よく知られており、よく理解されており、非常に一般的です。ハッキングとは見なされず、回避する必要はありません。まれに、同じ名前のメンバーを定義する 2 つのインターフェイスをクラスが実装しているが、それらに異なる動作を与えたい場合でも必要です。
ただし、許可された入力値またはアクションを制限するすべての場合で、Liskov Substitution Principle (LSP) に違反します。私の例では、IMarkerInterface obj
パラメーターをConcreteObject
オブジェクトに制限します。その他の例としては、次のようなものがあります。オブジェクトが追加されCollection<T>
たときに例外をスローする。引数の型が間違っている場合にエラーをスローnull
する実装。IComparable.CompareTo
または、ReadOnlyCollection
その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);
}
}