2009-02-13 4 views
5

Terminé con algo así como el siguiente código en un proyecto en el que estoy trabajando. Pensé que era realmente extraño que me permitieran hacerlo, pero ahora estoy empezando a preguntarme qué es lo que probablemente sea un truco arquitectónico de mi parte que me condujo a esto.Físicamente extraño polimorfismo de la interfaz con la composición de la interfaz

Mis preguntas para usted son:

  • ¿Qué es exactamente se llama esto?
  • ¿Cuáles son algunos usos del mundo real de esto?
  • ¿Por qué alguien querría hacer esto?

Aquí están mis Interfaces:

namespace ThisAndThat 
{ 
    public interface ICanDoThis 
    { 
     string Do(); 
    } 

    public interface ICanDoThat 
    { 
     string Do(); 
    } 

    public interface ICanDoThisAndThat : ICanDoThis, ICanDoThat 
    { 
     new string Do(); 
    } 
} 

Ésta es mi clase concreta:

namespace ThisAndThat 
{ 
    public class CanDoThisAndThat : ICanDoThisAndThat 
    { 
     public string Do() 
     { 
      return "I Can Do This And That!"; 
     } 

     string ICanDoThis.Do() 
     { 
      return "I Can Do This!"; 
     } 

     string ICanDoThat.Do() 
     { 
      return "I Can Do That!"; 
     } 
    } 
} 

Y mi superado los ensayos:

using Xunit; 

namespace ThisAndThat.Tests 
{ 
    public class ThisAndThatTests 
    { 
     [Fact] 
     public void I_Can_Do_This_And_That() 
     { 
      ICanDoThisAndThat sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do This And That!", sut.Do()); 
     } 

     [Fact] 
     public void I_Can_Do_This() 
     { 
      ICanDoThis sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do This!", sut.Do()); 
     } 

     [Fact] 
     public void I_Can_Do_That() 
     { 
      ICanDoThat sut = new CanDoThisAndThat(); 

      Assert.Equal("I Can Do That!", sut.Do()); 
     } 

    } 
} 

Respuesta

5

No hay absolutamente nada de malo en este código (siempre que no sea confuso para sus usuarios), y no es un patrón con ningún nombre con el que esté familiarizado. CanDoThisAndThat implementa dos interfaces, por lo que los clientes pueden usarlo de cualquier manera.

.NET permite que las interfaces se implementen de esta forma, conocida como implementación de interfaz explícita .

aplicación explícita de interfaces es útil cuando:

  1. Dos interfaces tienen la misma definición de miembro de
  2. Es necesario implementar una interfaz, pero no quieren dar a conocer que un miembro en particular está disponible para que el código de cliente no ha declarado una referencia utilizando la interfaz tipo

Un ejemplo del caso 2 del .NET framework es ICollection.SyncLock.List<T> implementa ICollection sin embargo, el siguiente código no se compilará debido a que el miembro ha intencionadamente sido 'oculta' como los diseñadores del BCL ya no abogar colecciones de bloqueo de esta manera:

List<object> list = new List<object>(); 

lock (list.SyncRoot) // compiler fails here 
{ 
    // ... 
} 

Cualquier código heredado de este formato seguirá funcionando , porque la referencia es de tipo ICollection explícitamente:

ICollection list = new List<object>(); 

lock (list.SyncRoot) // no problem 
{ 
    // ... 
} 
+0

Gracias, que le da la respuesta, porque ya ha proporcionado el nombre exacto de la lo que está pasando. –

+0

Downvoted ya que tiene muchos errores en su respuesta. Primero, la clase 'CanDoThisAndThat' implementa TRES interfaces, no dos. 'ICanDothisAndThat' establece que, cuando se implemente, también debe implementar las otras dos interfaces. Además, SyncRoot no está explícitamente definido por implementaciones para ocultarlo y desalentar el uso, se hace generalmente para mantener fuera del sitio a los miembros que rara vez se usan, o si el hecho de que se implemente una interfaz no debe importar. Mire http://msdn.microsoft.com/en-us/library/system.collections.icollection.syncroot.aspx y http://msdn.microsoft.com/en-us/library/bb356596.aspx. – Andy

+0

En ningún lugar de esa documentación dice que no debe usar SyncLock, ni está marcado como Obsoleto, que es lo que realmente se hace cuando algo ya no se debe usar. – Andy

4

Cada tipo tiene un interface mapping (que puede ser recuperado con Type.GetInterfaceMap si nt mirarlo con reflejo). Esto básicamente dice: "Cuando se invoca el método X en la interfaz Y, este método Z es el que se llama". Tenga en cuenta que, aunque no es compatible con C#, es posible que el método de destino de asignación tenga un nombre diferente del nombre del método de interfaz. (VB lo admite explícitamente, creo).

En su caso, tiene tres métodos y cada uno de los tres métodos corresponde a un método en una de las interfaces involucradas.

Cuando el compilador emite una llamada a un método virtual a través de una interfaz, el IL generado dice algo así como "invoque a IFoo.Bar en este objeto" - y IFoo.Bar se resuelve utilizando el mapa de la interfaz.

En ocasiones puede necesitar usarlo si tiene firmas que difieren solo en el tipo de devolución, o si está implementando dos interfaces heterogéneas que tienen los mismos nombres de método pero deberían hacer cosas diferentes. Donde sea que puede evitarlo, ¡sí! Hace un código muy confuso.

Cuestiones relacionadas