C# 用派生接口实现C接口

C# 用派生接口实现C接口,c#,.net,inheritance,interface,C#,.net,Inheritance,Interface,在以下示例类中,SomeClass未实现接口。为什么我不能通过传递一个实现基本需求的派生接口来实现这一点呢。无论传递什么实例,它仍然会实现基,我是否遗漏了什么 namespace Test { public interface IBaseInterface { void DoBaseStuff(); } public interface IChildInterface : IBaseInterface { void DoC

在以下示例类中,SomeClass未实现接口。为什么我不能通过传递一个实现基本需求的派生接口来实现这一点呢。无论传递什么实例,它仍然会实现基,我是否遗漏了什么

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)
        {
        }
    }
}
这违反了法律

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

这违反了

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

来自:

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

该方法在实际工程中得到了应用

void DoSomething(IChildInterface baseInterface)
与接口中的签名不相同:

void DoSomething(IBaseInterface baseInterface)
IchilInterface和IbasInterface的类型不同。因此,派生类并没有实现接口的所有方法,因此会出现编译错误

有关将此作为限制而不是编译器理解继承的可能逻辑,请参见SLakes answer中的Liskov替换原则:

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

该方法在实际工程中得到了应用

void DoSomething(IChildInterface baseInterface)
与接口中的签名不相同:

void DoSomething(IBaseInterface baseInterface)
IchilInterface和IbasInterface的类型不同。因此,派生类并没有实现接口的所有方法,因此会出现编译错误


对于一个可能的限制,而不是编译器理解继承的逻辑,请参见SLakes answer中的Liskov替换原则,该限制存在,因为ISomeInterface期望任何IBaseInterface都能满足约定。也就是说,如果您具备以下条件:

public interface IBase {}
public interface IChildA : IBase {}
public interface IChildB : IBase {}
以及一个需要IBase的接口:

然后根据需要在派生类中对此进行限制:

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调整为泛型,并接受作为IBase派生的T:

这有一个有趣的副作用:无论何时调用IFoofoo.Bar,它都会使用IBase,而当调用foo.Bar时,它都会使用IChildA或IBase。这意味着它满足契约,同时还具有派生接口特定的方法。如果要进一步隐藏BarIBase方法,可以显式实现IFoo:

void IFoo.Bar(IBase val) { }
这在您的代码中创建了更加不一致的行为,因为现在IFoofoo.Bar与foo.Bar完全不同,但我将决定权留给您

这意味着,在本节的第二个版本中,foo.Barnew ChildB;现在无效,因为IChildB不是IChildA

为什么我不能通过传递一个实现基本需求的派生接口来实现这一点呢。无论传递什么实例,它仍然会实现基,我是否遗漏了什么

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)
        {
        }
    }
}
这是不允许的,因为我上面提到的推理,IFoo.Bar需要任何IBase,而您希望进一步将类型约束为IChildA,它不是IBase的超级接口,即使是这样,也不允许,因为它违反了接口实现,尽管您可以更容易地定义第二种方法,它可以满足您的需要


请记住,当您实现一个接口时,您订阅了一个合同,并且C不会让您违反该合同。

此限制存在,因为ISomeInterface希望任何IBaseInterface都能满足该合同。也就是说,如果您具备以下条件:

public interface IBase {}
public interface IChildA : IBase {}
public interface IChildB : IBase {}
以及一个需要IBase的接口:

然后根据需要在派生类中对此进行限制:

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调整为泛型,并接受作为IBase派生的T:

这有一个有趣的副作用:无论何时调用IFoofoo.Bar,它都会使用IBase,而当调用foo.Bar时,它都会使用IChildA或IBase。这意味着它满足契约,同时还具有派生接口特定的方法。如果要进一步隐藏BarIBase方法,可以显式实现IFoo:

void IFoo.Bar(IBase val) { }
这在您的代码中创建了更加不一致的行为,因为现在IFoofoo.Bar与foo.Bar完全不同,但我将决定权留给您

这意味着,在本节的第二个版本中,foo.Barnew ChildB;现在无效,因为IChildB不是IChi 阿尔达

为什么我不能通过传递一个实现基本需求的派生接口来实现这一点呢。无论传递什么实例,它仍然会实现基,我是否遗漏了什么

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)
        {
        }
    }
}
这是不允许的,因为我上面提到的推理,IFoo.Bar需要任何IBase,而您希望进一步将类型约束为IChildA,它不是IBase的超级接口,即使是这样,也不允许,因为它违反了接口实现,尽管您可以更容易地定义第二种方法,它可以满足您的需要


请记住,当您实现一个接口时,您订阅了一个合同,C不会让您违反该合同。

如果您可以这样做,那么您可以这样做:

IAnimal cat = new Cat();
IAnimalTrainer dogTrainer = new DogTrainer();
dogTrainer.Train(cat);

一名飞行员可以训练任何一名飞行员。但是驯狗师只能训练狗。因此,DogTrainer实现IAnimalTrainer接口是非法的。

如果您可以这样做,那么您可以这样做:

IAnimal cat = new Cat();
IAnimalTrainer dogTrainer = new DogTrainer();
dogTrainer.Train(cat);

一名飞行员可以训练任何一名飞行员。但是驯狗师只能训练狗。因此,DogTrainer实现IAnimalTrainer接口是非法的。

您应该更改一些接口以使用实现IBaseInterface的某种类型, 然后更改方法签名以使用SomeClass想要的任何子级

public interface ISomeInterface<TSomeChild> where TSomeChild : IBaseInterface
{
    void DoSomething(TSomeChild baseInterface);
}

public class SomeClass : ISomeInterface<IChildInterface>
{
    public void DoSomething(IChildInterface baseInterface)
    {
    }
}

您应该更改一些接口以使用实现IBaseInterface的类型, 然后更改方法签名以使用SomeClass想要的任何子级

public interface ISomeInterface<TSomeChild> where TSomeChild : IBaseInterface
{
    void DoSomething(TSomeChild baseInterface);
}

public class SomeClass : ISomeInterface<IChildInterface>
{
    public void DoSomething(IChildInterface baseInterface)
    {
    }
}

虽然这在更一般的方面是正确的,但我认为实际的原因是C编译器只需要1对1的实现。如果情况相反,即接口需要子接口,实现允许基接口,那么它不会违反Liskov,但这也不合法。虽然这在更一般的情况下是正确的,但我认为实际原因是C编译器只需要1对1实现。如果情况相反,即接口需要子接口,实现允许基本接口,则不会违反Liskov,但这也不合法。非常好的解释,感谢您的解决方案!非常好的解释,感谢您的解决方案!