2010-04-15 8 views
12

Esta es una extensión de this question y probablemente incluso sea un duplicado de alguna otra pregunta (Si es así, por favor perdóneme). Me see from MSDN que los genéricos se utilizan por lo general con coleccionesGenerics vs inheritance (cuando no hay clases de colección involucradas)

El uso más común para genéricos clases es con colecciones como listas enlazadas, tablas hash, pilas, colas, árboles y así sucesivamente, donde operaciones tales como la adición y la eliminación de elementos de la colección es realizada de la misma manera independientemente del tipo de datos que están almacenados.

Los ejemplos que he visto también validan la declaración anterior.

¿Alguien puede dar un uso válido de genéricos en un escenario de la vida real que no involucre ninguna colección?

pedante, yo estaba pensando en hacer un ejemplo que no implica colecciones

public class Animal<T> 
{ 
    public void Speak() 
    { 
     Console.WriteLine("I am an Animal and my type is " + typeof(T).ToString()); 
    } 

    public void Eat() 
    { 
     //Eat food 
    } 
} 

public class Dog 
{ 
    public void WhoAmI() 
    { 
     Console.WriteLine(this.GetType().ToString()); 

    } 
}   

y "Un animal de tipo perro" será

Animal<Dog> magic = new Animal<Dog>();

Es totalmente posible tener Dog siendo heredado de Animal (asumiendo una versión no genérica de Animal) Dog:Animal Por lo tanto Doges unAnimal

Otro ejemplo que estaba pensando era un BankAccount. Puede ser BankAccount<Checking>, BankAccount<Savings>. Esto puede ser Checking:BankAccount y Savings:BankAccount.

¿Existen mejores prácticas para determinar si deberíamos ir con genéricos o con herencia?

+1

utilizar la herencia cuando cada vez que necesita extender una clase. En su ejemplo, tiene Animal como genérico, es decir, puede ser del tipo que lo asigne. Los genéricos proporcionan a su programa una forma de utilizar una interfaz común para realizar operaciones. – Kaili

Respuesta

8

Probablemente obtendrá algunas respuestas mejores, pero mientras tanto considere esto: Las clases genéricas implican una relación "de" entre la clase genérica y la clase de parámetro.

Todos los perros son animales, por lo que comparten ciertos atributos/cualidades con todos los demás animales. Si usa herencia, entonces es muy fácil implementar esas cualidades comunes en la clase Animal y agregar cualidades en las clases descendentes.Pero si hacerlo operativo Animal (Of Dog), entonces:

  1. Su clase de perro no es realmente un perro totalmente cualificado/animal por sí mismo, ya que sus "cualidades animales" están contenidos en la clase Animal (Of T). El perro debe estar atado con el animal en una relación padre-hijo.
  2. Su clase Animal no es realmente un animal: no puede crear un método que acepte Animals como argumento, porque no puede referirse a la clase globalizada Animal (Of T). En realidad, es una familia de clases con un comportamiento común, no una superclase. Pierdes el beneficio de tratar con animales fuera de la clase Animal (Of T).

Pero aquí es cómo, en mi humilde opinión, se debe pensar en los genéricos: Piense en una clase MedicalDoctor(Of T). Veterinarian(Of T as Animal) sería heredar de MedicalDoctor(Of Animal). DogVeterinarian heredaría de Veterinarian(Of Dog).

Punto clave: la clase genérica y la clase de parámetro no están estrechamente relacionadas y son co-dependientes, sino que coexisten.

BTW, si quiere ver un buen uso de genéricos que no sean de recopilación, solo tenga en cuenta los delegados que tenemos: Acción (De T), Func (Of TResult), Comparación (Of T), EventHandler (Of TEventArgs) , convertidor (De TSource, TResult) ... y las interfaces: IEqualityComparer (Of T), IComparer (Of T) ...

3

Un ejemplo del mundo real que se conoce está en el WCF Channel Factory.

Desde la página:

public sealed class Test 
{ 
    static void Main() 
    { 
     // Code not shown. 
    } 

    public void Run() 
    { 
     // This code is written by an application developer. 
     // Create a channel factory. 
     BasicHttpBinding myBinding = new BasicHttpBinding(); 

     EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1"); 

     ChannelFactory<IMath> myChannelFactory = new ChannelFactory<IMath>(myBinding, myEndpoint); 

     // Create a channel. 
     IMath wcfClient1 = myChannelFactory.CreateChannel(); 
     double s = wcfClient1.Add(3, 39); 
     Console.WriteLine(s.ToString()); 
     ((IClientChannel)wcfClient1).Close(); 

     // Create another channel. 
     IMath wcfClient2 = myChannelFactory.CreateChannel(); 
     s = wcfClient2.Add(15, 27); 
     Console.WriteLine(s.ToString()); 
     ((IClientChannel)wcfClient2).Close(); 
     myChannelFactory.Close(); 
    } 
} 

La forma en que pienso de los genéricos es que son un representan un tipo que una clase está actuando sobre. Por ejemplo, ChannelFactory construye fábricas de tipo T. La herencia representa una relación jerárquica entre tipos. Un perro es un animal, un golden retriever es tanto un perro como un animal.

3

Nullable<T> es genérico, no es una clase de colección, y no puede implica herencia ya que se relaciona con struct s.

Las familias de los delegados genéricos son bastante agradable - EventHandler<T>, Action<...]>, Func<[...]> - es mucho más claro lo que es Func<int,bool> en lugar de alguna costumbre IdPredicate o lo que sea.

+0

Si lo gira sobre su cabeza, agítelo, agítelo y bizquea * justo de la manera correcta *, entonces podría interpretar 'Nullable ' como una colección de ninguno o exactamente un elemento. Aunque, a menos que seas un programador de Haskell, probablemente no se te ocurra :-) –

1

Está confundiendo el aspecto "is-a" de la herencia con el aspecto "de" de los genéricos.

Los genéricos implican la igualdad de operaciones en todas las clases, no solo que las operaciones existen polimórficamente.

En su ejemplo de Animal, una instancia de Animal<Dog> no tiene un método WhoAmI, mientras que una instancia de Dog : Animal lo haría.

0

Usa la herencia en tu situación, por favor.
Si una clase puede describirse correctamente por otra clase [por ejemplo, un cuadrado puede describirse como un rectángulo] el cuadrado debe heredar/extenderse de la búsqueda de rectángulo. De lo contrario, te estás metiendo en un lío.

Uso GenericClass a decir this is a GenericClass object of tType-s Uso Square: Rectángulo para decir this is a Square, which is also a Rectangle

En su caso:
uso del perro: Animal en el sentido de this is a Dog, which is also an Animal

Cuestiones relacionadas