在以下示例类" SomeClass"没有实现" ISomeInterface"。为什么我不能通过传递更实现基本要求的派生接口来实现这一点。无论通过什么实例,它仍然会实现基础,我错过了什么?
namespace Test
{
public interface IBaseInterface
{
void DoBaseStuff();
}
public interface IChildInterface : IBaseInterface
{
void DoChildStuff();
}
public interface ISomeInterface
{
void DoSomething(IBaseInterface baseInterface);
}
public class SomeClass : ISomeInterface
{
public void DoSomething(IChildInterface baseInterface)
{
}
}
}
答案 0 :(得分:2)
这违反了Liskov substitution principle。
ISomeInterface
保证可以使用任何 IBaseInterface
实例调用该方法。您的实现不能将其限制为仅接受IChildInterface
接口。
答案 1 :(得分:1)
来自MSDN:
当类或结构实现接口时,类或结构必须为接口定义的所有成员提供实现
派生
中的此方法void DoSomething(IChildInterface baseInterface)
与界面中的签名不同:
void DoSomething(IBaseInterface baseInterface)
IChildInterface
和IBaseInterface
的类型不同。因此,派生类不实现接口的所有方法,并且您得到编译错误。
对于一个可能的逻辑,将此作为限制,而不是编译器理解继承,请参阅Liskov的替换原则,如SLakes回答
答案 2 :(得分:1)
存在此限制是因为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
或< / strong> IBase
。这意味着它满足合同,同时还具有特定于派生接口的方法。如果你想&#34;隐藏&#34; 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#将不让您违反该合同。
答案 3 :(得分:0)
如果你能做到这一点,那么你可以这样做:
IAnimal cat = new Cat();
IAnimalTrainer dogTrainer = new DogTrainer();
dogTrainer.Train(cat);
IAnimalTrainer
可以训练任何IAnimal
。但是DogTrainer
只能训练Dog
。因此DogTrainer
实现IAnimalTrainer
接口是非法的。
答案 4 :(得分:0)
你应该改变一些接口来使用一些实现IBaseInterface的类型, 然后更改方法签名以使用您的SomeClass想要的任何一个孩子。
public interface ISomeInterface<TSomeChild> where TSomeChild : IBaseInterface
{
void DoSomething(TSomeChild baseInterface);
}
public class SomeClass : ISomeInterface<IChildInterface>
{
public void DoSomething(IChildInterface baseInterface)
{
}
}