2012-01-16 14 views
7

Mam następujący kod:generyczne interfejsy i polimorfizm

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 kiedy medium kod tylko przedstawieniu struktury. Teraz muszę associationDictionary że powróci IOperandFactory do wymaganego Type: coś takiego:

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

możesz pomóc mi osiągnąć to, czy jest to możliwe?

Odpowiedz

7

Aby to zrobić, potrzebny jest nietypowy interfejs (zwykle oprócz ogólnego interfejsu), tj. Nietypowy Operand, z Operand<T> : Operand (może to być również interfejs) i nietypowy. IOperandFactory z IOperandFactory<T> : IOperandFactory. Jedyną inną opcją jest przechowywanie Dictionary<Type, object> i sprawdzenie, czy dzwoniący jest obsadzony w razie potrzeby.

Oto nierodzajową podejście:

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

Dziękuję za szybką odpowiedź. – Danil

+0

@Danil Edytowałem w pełnym przykładzie, jeśli pomaga –

+0

Tak, dziękuję, myślę, że będzie to przydatne również dla innych użytkowników. – Danil

2

Jeśli dobrze rozumiem, próbujesz przechowywania kolekcji typów generycznych, gdzie ogólne parametry typu mogą się różnić. Jeśli tak jest, to nie jest możliwe bezpośrednio, co ilustruje poniższy przykład ilustruje:

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

Co powinno być oczywiste, tutaj jest to, że nie można wywnioskować, jaki typ parametru w użyciu. Zamiast (w odniesieniu do swojej przykład), może chcesz coś takiego zamiast:

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

To może nie być najbardziej eleganckich rozwiązań, ale to pozwala na przechowywanie różnych typów generycznych w tej samej kolekcji. Problem z tym jednak polega na tym, że osoba dzwoniąca uzyskująca dostęp do takiej kolekcji musiałaby wiedzieć, do którego typu należy przesyłać. Na przykład:

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

Więc z tym, można uzyskać stosując DoubleFactory:

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