具有派生接口的C#接口实现 [英] C# interface implementation with derived interface

查看:103
本文介绍了具有派生接口的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.


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?

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#接口实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆