2012-01-16 18 views
7

Ho seguente codice:interfacce generiche e 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 
    } 
} 

ho simlified codice per mostrare solo la struttura. Ora ho bisogno associationDictionary che tornerà IOperandFactory per richieste Type: Qualcosa di simile:

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

Potrebbe aiutarmi a realizzarlo se è possibile?

risposta

7

Per fare ciò, è necessario disporre di un'interfaccia non generica (in genere oltre all'interfaccia generica), ad esempio una non generica Operand, con Operand<T> : Operand (potrebbe anche essere un'interfaccia) e una non generica IOperandFactory con IOperandFactory<T> : IOperandFactory. L'unica altra opzione è quella di memorizzare un Dictionary<Type, object> e fare in modo che il cast del chiamante sia necessario.

Ecco l'approccio non generico:

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

Grazie per la risposta rapida. – Danil

+0

@Danil Ho modificato un esempio completo, se aiuta –

+0

Sì, grazie, penso che sarà utile anche per altri utenti. – Danil

2

Se ho capito bene, si sta tentando di memorizzare una raccolta di tipi generici, in cui i parametri di tipo generico possono variare. Se questo è il caso, non è direttamente possibile, come il seguente esempio illustra:

// 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? ... */ >>(); 

quello che dovrebbe essere evidente qui, è che non è possibile dedurre quale parametro tipo usare. Invece (per quanto riguarda il tuo esempio), si può decidere qualcosa di simile a questo, invece:

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

Questo non può essere il più elegante di soluzioni, ma permetterebbe di memorizzare diversi tipi generici nella stessa collezione. Un problema con questo, tuttavia, è che il chiamante che accede a una raccolta di questo tipo avrebbe bisogno di sapere a quale tipo eseguire il cast. Per esempio:

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

Quindi, con questo, è possibile ottenere il DoubleFactory utilizzando:

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