本文介绍了具有派生接口的C#接口实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的示例类中,"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)
        {
        }
    }
}
解决方案

之所以存在此限制,是因为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调整为通用,并接受作为IBase派生的T:

    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).Barfoo.Bar完全不同 ,但我将决定权留给您. /p>

    这意味着,对于本节的第二个版本,foo.Bar(new ChildB());现在无效,因为IChildB not IChildA.


由于我上面提到的原因,这是不允许的,IFoo.Bar期望任何 IBase,而您想进一步将类型限制为IChildA ,它不是IBase的超级接口,即使是IBase的超级接口,也可以使用,因为它违反了接口的实现,尽管您可以更容易地进行定义,此时第二种方法可以满足您的需求.

请记住,当您实现interface时,您订阅了合同,而C#将允许您违反该合同.

In the following sample class "SomeClass" does not implement "ISomeInterface". Why can't I implement this by passing a more derived interface which does implement the base requirement. Whatever instance would be passed it would still implement the base, am I missing something?

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)
        {
        }
    }
}
解决方案

This restriction exists because the ISomeInterface expects that any IBaseInterface will satisfy the contract. That is, if you have the following:

public interface IBase {}
public interface IChildA : IBase {}
public interface IChildB : IBase {}

And an interface that expects IBase:

public interface IFoo { void Bar(IBase val); }

Then restricting this in a derived class as you would like:

public class Foo : IFoo { public void Bar(IChildA val) {} }

Would create the following problem:

IChildB something = new ChildB();
IFoo something = new Foo();
something.Bar(something); // This is an invalid call

As such, you're not implementing the contract you said you would.

In this situation, you have two simple options:

  • Adjust IFoo to be generic, and accept a T that is a derivation of IBase:

    public interface IFoo<T> where T : IBase { void Bar(T val); }
    public class Foo : IFoo<IChildA> { public void Bar(IChildA val) {} }
    

    Of course, this means that Foo can no longer accept any IBase (including IChildB).

  • Adjust Foo to implement IFoo, with an additional utility method for void Bar(IChildA val):

    public class Foo : IFoo
    {
        public void Bar(IBase val) {}
        public void Bar(IChildA val) {}
    }
    

    This has an interesting side-effect: whenever you call ((IFoo)foo).Bar it will expect IBase, and when you call foo.Bar it will expect IChildA or IBase. This means it satisfies the contract, while also having your derived-interface-specific method. If you want to "hide" the Bar(IBase) method more, you could implement IFoo explicitly:

    void IFoo.Bar(IBase val) { }
    

    This creates even more inconsistent behavior in your code, as now ((IFoo)foo).Bar is completely different from foo.Bar, but I leave the decision up to you.

    This means, with the second version in this section, that foo.Bar(new ChildB()); is now invalid, as IChildB is not an IChildA.


This is not allowed because of the reasoning I mentioned above, IFoo.Bar expects any IBase, whereas you want to further constrain the type to IChildA, which is not a super-interface of IBase, and even if it were it would not be allowed because it violates the interface implementation, though you could more easily define a second method at that point that does what you want.

Keep in mind that when you implement an interface, you subscribe to a contract, and C# will not let you violate that contract.

这篇关于具有派生接口的C#接口实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-23 10:02