2012-01-16 29 views
7

He siguientes códigos:interfaces genéricas y polimorfismo

public abstract class Operand<T> 
{ 
    public T Value { get; protected set; } 

    public bool IsEmpty { get; protected set; } 

    public override string ToString() 
    { 
     return IsEmpty ? Value.ToString() : string.Empty; 
    } 
} 
public class DoubleOperand : Operand<Double> {} 

public interface IOperandFactory<T> 
    { 
     Operand<T> CreateEmptyOperand(); 
     Operand<T> CreateOperand(T value); 
    } 

public class DoubleFactory: IOperandFactory<double> 
{ 
    public Operand<Double> CreateEmptyOperand() 
    { 
     //implementation 
    } 

    public Operand<Double> CreateOperand(double value) 
    { 
     //implementation 
    } 
} 

I simlified código para mostrar sólo la estructura. Ahora necesito associationDictionary que devolverá IOperandFactory para Type requerido: Algo como esto:

var factoryDict = 
new Dictionary<Type, IOperandFactory<>>() { { typeof(double), new DoubleFactory() } }; 

Podría ayudar a mí para lograr si es posible?

Respuesta

7

Para hacer eso, necesitaría tener una interfaz no genérica (generalmente además de la interfaz genérica), es decir, una Operand no genérica, con Operand<T> : Operand (también podría ser una interfaz), y una no genérica IOperandFactory con IOperandFactory<T> : IOperandFactory. La única otra opción es almacenar un Dictionary<Type, object>, y hacer que la persona que llama lo arroje según sea necesario.

Aquí es el enfoque no genérico:

using System.Collections.Generic; 
using System; 
public interface IOperand 
{ 
    object Value { get; } 
    bool IsEmpty { get; } 
} 
public abstract class Operand<T> : IOperand 
{ 
    public T Value { get; protected set; } 
    object IOperand.Value { get { return Value; } } 
    public bool IsEmpty { get; protected set; } 
    public override string ToString() 
    { 
     return IsEmpty ? Value.ToString() : string.Empty; 
    } 
} 
public class DoubleOperand : Operand<double> { } 

public interface IOperandFactory 
{ 
    IOperand CreateEmptyOperand(); 
    IOperand CreateOperand(object value); 
} 
public interface IOperandFactory<T> : IOperandFactory 
{ 
    new Operand<T> CreateEmptyOperand(); 
    Operand<T> CreateOperand(T value); 
} 

public class DoubleFactory : IOperandFactory<double> 
{ 
    public Operand<double> CreateEmptyOperand() 
    { 
     throw new NotImplementedException(); 
    } 
    IOperand IOperandFactory.CreateEmptyOperand() { 
     return CreateEmptyOperand(); 
    } 

    IOperand IOperandFactory.CreateOperand(object value) { 
     return CreateOperand((double)value); 
    } 
    public Operand<double> CreateOperand(double value) 
    { 
     throw new NotImplementedException(); 
    } 
} 

static class Program 
{ 
    static void Main() 
    { 
     var factoryDict = new Dictionary<Type, IOperandFactory> { 
      {typeof (double), new DoubleFactory()} 
     }; 
    } 
} 
+0

Gracias por la respuesta rápida. – Danil

+0

@Danil Edité en un ejemplo completo, si ayuda –

+0

Sí, gracias, creo que también será útil para otros usuarios. – Danil

2

Si he entendido bien, que están tratando de almacenar una colección de tipos genéricos, donde los parámetros de tipo genérico pueden variar. Si este es el caso, no es directamente posible, como ilustra el siguiente ejemplo:

// You have lists of different types: 
List<double> doubleCollection = new List<double>(); 
List<string> stringCollection = new List<string>(); 

// Now to store generically: 
var collection = new List<List< /* ... Which type parameter to use? ... */ >>(); 

Lo que debería ser evidente aquí, es que no es posible deducir que el parámetro tipo de uso. En su lugar (con respecto a su ejemplo), es posible que desee algo como esto en su lugar:

public interface IOperand 
{ 
} 

public interface IOperand<T> 
{ 
} 

public interface IOperandFactory 
{ 
    IOperand CreateEmptyOperand(); 
    IOperand CreateOperand(object value); 
} 

public interface IOperandFactory<T> : IOperandFactory 
{ 
    new IOperand<T> CreateEmptyOperand(); 
    IOperand<T> CreateOperand(T value); 
} 

public class DoubleFactory : IOperandFactory<double> 
{ 
    public IOperand<double> CreateEmptyOperand() 
    { 
     throw new NotImplementedException(); 
    } 

    public IOperand<double> CreateOperand(double value) 
    { 
     throw new NotImplementedException(); 
    } 

    IOperand IOperandFactory.CreateEmptyOperand() 
    { 
     throw new NotImplementedException(); 
    } 

    public IOperand CreateOperand(object value) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class SomeContainer 
{ 
    public SomeContainer() 
    { 
     var factoryDict = new Dictionary<Type, IOperandFactory>() 
     { 
      { typeof(double), (IOperandFactory)new DoubleFactory() } 
     }; 
    } 
} 

esto puede no ser la más elegante de las soluciones, pero permitiría que le permite almacenar diferentes tipos genéricos de la misma colección. Un problema con esto, sin embargo, es que la persona que llama que accede a dicha colección necesitaría saber a qué tipo enviarla. Por ejemplo:

// ... Inside SomeContainer ... 
public IOperandFactory<T> GetFactory<T>() 
{ 
    return (IOperandFactory<T>)factoryDict[typeof(T)]; 
} 

Así que con esto, se puede obtener el DoubleFactory usando:

IOperandFactory<double> doubleFactory = mSomeContainerInstance.GetFactory<double>(); 
IOperand<double> emptyOperand = doubleFactory.CreateEmptyOperand(); 
IOperand<double> filledOperand = doubleFactory.CreateOperand(1.0d);