为什么要使用显式接口实现来调用受保护的方法?

发布于 2024-07-09 15:49:16 字数 832 浏览 5 评论 0原文

codeplex,我发现有一个类显式实现接口是很常见的。 然后,显式实现的方法/属性调用另一个具有相同名称的“受保护虚拟”方法/属性。

例如,

public class MvcHandler : IHttpHandler, IRequiresSessionState 
{
    protected virtual bool IsReusable 
    {
        get 
        {
           return false;
        }
    }

    bool IHttpHandler.IsReusable 
    {
        get 
        {
           return IsReusable;
        }
    }
}

我现在确定这种编程有什么好处。 对我来说,我更喜欢隐式实现 IHttpHandler 接口。

我猜作者只是不希望 MvcHandler 有一个公共属性 IsResuable。 仅当 MvcHandler 实例被视为 IHttpHandler 时才能使用属性 IsReusable。 尽管如此,我还是不确定作者为什么要这样做。

有人知道这种接口实现方式的更多好处吗?

When browsing ASP.NET MVC source code in codeplex, I found it is common to have a class explicitly implementing interface. The explicitly implemented method/property then invoke another "protected virtual" method/property with same name.

For example,

public class MvcHandler : IHttpHandler, IRequiresSessionState 
{
    protected virtual bool IsReusable 
    {
        get 
        {
           return false;
        }
    }

    bool IHttpHandler.IsReusable 
    {
        get 
        {
           return IsReusable;
        }
    }
}

I'm now sure what's the benefit of this kind of programming. For me, I prefer to just implicitly implement the interface IHttpHandler.

I guess the author just don't want MvcHandler has a public property IsResuable. The property IsReusable can only be used when instance of MvcHandler is treated as a IHttpHandler. Still, I'm not sure why the author what this way.

Anybody know more benefits about this style of interface implementation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦明 2024-07-16 15:49:16

嗯,不是特定于 MVC,但这种方法允许您保持核心公共 API 干净。 如果存在不同接口/等具有相同名称和名称的风险,它也很有用。 签名,但含义不同。 事实上,这种情况很少见。

它还允许您提供一个实现,您希望在子类中更改返回类型:(

为简单起见选择ICloneable - 不要因为它是一个定义不明确的接口这一事实而烦恼。一个更好的例子是像 DbCommand 等,它可以做到这一点 - 但这很难在一个简短的例子中展示)

class Foo : ICloneable
{
    public Foo Clone() { return CloneCore(); }
    object ICloneable.Clone() { return CloneCore(); }
    protected virtual Foo CloneCore() { ... }
}

class Bar : Foo
{
    protected override Foo CloneCore() { ... }
    public new Bar Clone() { return (Bar)CloneCore(); }
}

如果我们使用了公共虚拟方法,我们将无法覆盖在基类中使用new,因为您不能同时执行这两种操作:

class A
{
    public virtual A SomeMethod() { ... }
}
class B : A
{
    public override A SomeMethod() { ... }
    //Error 1   Type 'B' already defines a member called 'SomeMethod' with the same parameter types
    public new B SomeMethod() { ... }
}

使用受保护的虚拟方法,任何用法:

  • Foo.Clone()
  • Bar.Clone()
  • ICloneable.Clone()

都使用具体类型的正确 CloneCore() 实现。

Well, not specific to MVC, but this approach allows you to keep the core public API clean. It is also useful if there is ever a risk of different interfaces / etc having the same name & signature, but different meaning. In reality this is rare.

It also allows you to provide an implementation where you want the return type to change in subclasses:

(ICloneable chosen for simplicity - don't get hung up on the fact that it is a poorly defined interface... a better example would have been things like DbCommand etc, which do this - but that is harder to show in a short example)

class Foo : ICloneable
{
    public Foo Clone() { return CloneCore(); }
    object ICloneable.Clone() { return CloneCore(); }
    protected virtual Foo CloneCore() { ... }
}

class Bar : Foo
{
    protected override Foo CloneCore() { ... }
    public new Bar Clone() { return (Bar)CloneCore(); }
}

If we had used a public virtual method, we wouldn't be able to override it and use new in the base-class, as you aren't allowed to do both:

class A
{
    public virtual A SomeMethod() { ... }
}
class B : A
{
    public override A SomeMethod() { ... }
    //Error 1   Type 'B' already defines a member called 'SomeMethod' with the same parameter types
    public new B SomeMethod() { ... }
}

Using the protected virtual approach, any usage:

  • Foo.Clone()
  • Bar.Clone()
  • ICloneable.Clone()

all use the correct CloneCore() implementation for the concrete type.

半寸时光 2024-07-16 15:49:16

如果一个类显式实现了 IFoo.Bar,并且派生类需要 IFoo.Bar 来执行不同的操作,则派生类将无法调用基类该方法的类实现。 不重新实现 IFoo.Bar 的派生类可以通过 ((IFoo)this).Bar() 调用基类实现,但如果派生类重新实现 IFoo.Bar(因为它必须这样做才能改变其行为)上述调用将转到派生类重新实现,而不是基类实现。 即使 ((IFoo)(BaseType)this).bar 也无济于事,因为将引用强制转换为接口类型将丢弃有关该引用类型的任何信息(而不是该引用的类型)实例实例)被强制转换。

显式接口实现除了调用受保护的方法之外什么都不做,可以避免此问题,因为派生类可以通过重写虚拟方法来更改接口方法的行为,同时保留调用其认为合适的基实现的能力。 恕我直言,C# 应该有一个显式接口实现,生成一个具有 CLS 兼容名称的虚拟方法,因此用 C# 编写显式实现 IFoo.Bar 的类的派生类的人可以说 override void IFoo.Bar,而用其他语言编写的人可能会说,例如Overrides Sub Explicit_IFoo_Bar(); 因为任何派生类都可以重新实现 IFoo.Bar,并且任何不重新实现 IFoo.Bar 的派生类都可以自行调用它,所以我不这样做我们看不到密封显式实现有任何有用的目的。

顺便说一句,在 vb.net 中,正常模式只是 Protected Overridable Sub IFoo_Bar() Implements IFoo.Bar,而不需要单独的虚拟方法。

If a class implements IFoo.Bar explicitly, and a derived class needs IFoo.Bar to do something different, there will be no way for the derived class to call the base-class implementation of that method. A derived class which does not re-implement IFoo.Bar could call the base-class implementation via ((IFoo)this).Bar(), but if the derived class re-implements IFoo.Bar (as it would have to in order to change its behavior) the aforementioned call would go to the derived-class re-implementation, rather than the base-class implementation. Even ((IFoo)(BaseType)this).bar wouldn't help, since casting a reference to an interface type will discard any information about the type of the reference (as opposed to the type of the instance instance) that was cast.

Having an explicit interface implementation do nothing but call a protected method avoids this problem, since a derived class can change the behavior of the interface method by overriding the virtual method, while retaining the ability to call the base implementation as it sees fit. IMHO, C# should have had an explicit interface implementation produce a virtual method with a CLS-compliant name, so someone writing in C# a derivative of a class that explicitly implemented IFoo.Bar could say override void IFoo.Bar, and someone writing in some other language could say, e.g. Overrides Sub Explicit_IFoo_Bar(); since any derived class can re-implement IFoo.Bar, and since any derived class which doesn't re-implement IFoo.Bar can call it on itself, I don't see that there's any useful purpose to having the explicit implementation be sealed.

Incidentally, in vb.net, the normal pattern would simply be Protected Overridable Sub IFoo_Bar() Implements IFoo.Bar, without need for a separate virtual method.

谷夏 2024-07-16 15:49:16
  1. 当显式实现成员时,不能通过类实例来访问它,而只能通过接口的实例来访问。 参考:显式接口实现教程
  2. As根据我的经验,如果接口实现者显式实现一个接口,那么在您从接口中删除方法后,他将收到编译器错误,而如果他/她隐式实现该接口,他将不会通知,并且该方法将保留在代码中。

原因 1 的示例:

public interface IFoo
{
    void method1();
    void method2();
}

public class Foo : IFoo
{
    // you can't declare explicit implemented method as public
    void IFoo.method1() 
    {
    }

    public void method2()
    {
    }

    private void test()
    {
        var foo = new Foo();
        foo.method1(); //ERROR: not accessible because foo is object instance
        method1(); //ERROR: not accessible because foo is object instance
        foo.method2(); //OK
        method2(); //OK

        IFoo ifoo = new Foo();
        ifoo.method1(); //OK, because ifoo declared as interface
        ifoo.method2(); //OK
    }
}
  1. When a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface. reference : Explicit Interface Implementation Tutorial
  2. As my experience if interface implementer explicitly implement an interface he will receive compiler error after you drop a method from interface while he will not notify if he/she implicitly implement it and the method will remain in the code.

sample for reason 1:

public interface IFoo
{
    void method1();
    void method2();
}

public class Foo : IFoo
{
    // you can't declare explicit implemented method as public
    void IFoo.method1() 
    {
    }

    public void method2()
    {
    }

    private void test()
    {
        var foo = new Foo();
        foo.method1(); //ERROR: not accessible because foo is object instance
        method1(); //ERROR: not accessible because foo is object instance
        foo.method2(); //OK
        method2(); //OK

        IFoo ifoo = new Foo();
        ifoo.method1(); //OK, because ifoo declared as interface
        ifoo.method2(); //OK
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文