Pergunta

Ao navegar código fonte ASP.NET MVC no codeplex , eu descobri que é comum ter uma classe de interface implementar explicitamente. O explicitamente implementado método / propriedade, em seguida, chamar outro "protegida virtual" método / propriedade com o mesmo nome.

Por exemplo,

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

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

Agora estou certo o que é o benefício deste tipo de programação. Para mim, eu prefiro a implementar apenas implicitamente a interface IHttpHandler.

Eu acho que o autor só não quero MvcHandler tem uma propriedade pública IsResuable . A propriedade IsReusable só pode ser usado quando exemplo de MvcHandler é tratada como um IHttpHandler . Ainda assim, eu não sei por que o autor o que este caminho.

Alguém sabe mais benefícios sobre este estilo de implementação interface?

Foi útil?

Solução

Bem, não é específico para MVC, mas esta abordagem permite que você manter o núcleo API pública limpa . Também é útil se há sempre um risco de diferentes interfaces / etc com o mesmo nome e assinatura, mas significado diferente. Na realidade, isso é raro.

Ele também permite que você forneça uma implementação onde deseja que o tipo de retorno para a mudança em subclasses:

(ICloneable escolhida pela simplicidade - não ficam penduradas sobre o fato de que é uma interface bem definida ... um exemplo melhor seria coisas como DbCommand etc, o que fazer isso - mas isso é mais difícil de mostrar em um pequeno exemplo)

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(); }
}

Se tivéssemos usado um método virtual público, não seria capaz de override ele e uso new na base de classe, como você não tem permissão para fazer as duas coisas:

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() { ... }
}

Usando a abordagem virtual protegido, qualquer uso:

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

todo o uso da implementação CloneCore() correto para o tipo de concreto.

Outras dicas

Se uma classe implementa IFoo.Bar explicitamente, e de derivados necessidades de classe IFoo.Bar fazer algo diferente, não haverá caminho para a classe derivada para chamar a implementação da classe base desse método. Uma classe derivada que não re-implementar IFoo.Bar poderia chamar a implementação da classe base via ((IFoo)this).Bar(), mas se a classe derivada re-implementa IFoo.Bar (como ele teria que, a fim de mudar o seu comportamento) a chamada acima mencionada iria para o derivado de classe re-implementação, em vez da implementação da classe base. Mesmo ((IFoo)(BaseType)this).bar não ajudaria, já que lançando uma referência a um tipo de interface irá descartar qualquer informação sobre o tipo de referência (em oposição ao tipo da instância instância) que foi fundido.

Ter uma implementação de interface explícita fazer nada, mas chamar um método protegido evita este problema, uma vez que uma classe derivada pode alterar o comportamento do método de interface, substituindo o método virtual, mantendo a capacidade de chamar a implementação base como lhe aprouver . IMHO, C # deve ter tido uma implementação de interface explícita produzir um método virtual com um nome compatível com CLS, então alguém escrita em C # um derivado de uma classe que IFoo.Bar explicitamente implementado poderia dizer override void IFoo.Bar, e alguém escrever em algum outro idioma poderia dizer, por exemplo, Overrides Sub Explicit_IFoo_Bar(); uma vez que qualquer classe derivada pode reimplementar IFoo.Bar, e uma vez que qualquer classe derivada que não reimplementar IFoo.Bar pode chamá-lo sobre si mesmo, não vejo que haja qualquer propósito útil a ter a implementação explícita ser selado.

A propósito, em vb.net, o padrão normal seria simplesmente Protected Overridable Sub IFoo_Bar() Implements IFoo.Bar, sem necessidade de um método virtual separada.

  1. Quando um membro é explicitamente implementado, ele não pode ser acessado através de uma instância de classe, mas apenas através de uma instância da interface. Referência: explícita implementação da interface Tutorial
  2. Como a minha experiência se interface de implementador explicitamente implementar uma interface que ele receberá erro do compilador depois de soltar um método a partir da interface enquanto ele não irá notificar se ele / ela implementá-lo implicitamente eo método permanecerá no código.

Exemplo de razão 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
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top