存在這種限制,因爲ISomeInterface
預計任何IBaseInterface
將滿足合同背後的邏輯。也就是說,如果你具備以下條件:
public interface IBase {}
public interface IChildA : IBase {}
public interface IChildB : IBase {}
這預計IBase
接口:
public interface IFoo { void Bar(IBase val); }
然後在派生類中限制這個,你想:
public class Foo : IFoo { public void Bar(IChildA val) {} }
會產生以下問題:
IChildB something = new ChildB();
IFoo something = new Foo();
something.Bar(something); // This is an invalid call
因此,你沒有執行你所說的合同。
在這種情況下,你有兩個簡單選項:
調整IFoo
是通用的,並接受T
這是IBase
推導:
public interface IFoo<T> where T : IBase { void Bar(T val); }
public class Foo : IFoo<IChildA> { public void Bar(IChildA val) {} }
當然,這意味着Foo
不能再接受任何IBase
(包括IChildB
)。
調整Foo
實施IFoo
,另外還有實用方法void Bar(IChildA val)
:
public class Foo : IFoo
{
public void Bar(IBase val) {}
public void Bar(IChildA val) {}
}
這有一個有趣的副作用:當你打電話((IFoo)foo).Bar
會想到IBase
,當你調用foo.Bar
它會期望IChildA
或IBase
。這意味着它滿足合同,同時也具有派生接口特定的方法。如果你想「隱藏」 Bar(IBase)
方法更多,你可以實現IFoo
明確:
void IFoo.Bar(IBase val) { }
這會在你的代碼更不一致的行爲,如現在((IFoo)foo).Bar
是完全foo.Bar
不同,但我把決定留給你。
這意味着,與本節中的第二個版本,即foo.Bar(new ChildB());
現在是無效的,因爲IChildB
是不一個IChildA
。
爲什麼我無法通過傳遞更多的衍生接口,確實實現了基地的要求實現這一點。無論哪個實例會通過它仍然會實現基地,我錯過了什麼?
這是不允許的,因爲我上面提到的推理,IFoo.Bar
預計任何IBase
,而要進一步約束類型IChildA
,這是不的IBase
超接口,即使它不允許,因爲它違反了接口實現,儘管你可以更容易地定義第二種方法,在那個時候你可以做到你想要的。
請記住,當你實現一個interface
,你訂閱合同一個,和C#將不讓你違反了該合同。
雖然這是更通用的方式,但我認爲這裏的實際原因是C#編譯器只需要1對1的實現。如果情況逆轉(即接口需要子接口,實現允許基接口),那麼它不會違反Liskov,但這也是不合法的。 –