带派生接口的C#接口实现

时间:2017-07-20 17:15:46

标签: c# .net inheritance interface

在以下示例类" 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)
        {
        }
    }
}

5 个答案:

答案 0 :(得分:2)

这违反了Liskov substitution principle

ISomeInterface保证可以使用任何 IBaseInterface实例调用该方法。您的实现不能将其限制为仅接受IChildInterface接口。

答案 1 :(得分:1)

来自MSDN

  

当类或结构实现接口时,类或结构必须为接口定义的所有成员提供实现

派生

中的此方法
void DoSomething(IChildInterface baseInterface)

与界面中的签名不同:

void DoSomething(IBaseInterface baseInterface)

IChildInterfaceIBaseInterface的类型不同。因此,派生类不实现接口的所有方法,并且您得到编译错误。

对于一个可能的逻辑,将此作为限制,而不是编译器理解继承,请参阅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,而您希望进一步约束类型到IChildAIBase的超级接口,即使它是不允许的,因为它违反了接口实现,尽管你可以更容易在那一点定义第二种方法,做你想做的事。

请注意,当您实施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)
    {
    }
}