10

Mi piacerebbe creare un TypeConverter per una classe generica, come questo:Impossibile creare un TypeConverter per un tipo generico

[TypeConverter(typeof(WrapperConverter<T>))] 
public class Wrapper<T> 
{ 

    public T Value 
    { 
     // get & set 
    } 

    // other methods 

} 


public class WrapperConverter<T> : TypeConverter<T> 
{ 

    // only support To and From strings 
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
     { 
     return true; 
     } 
     return base.CanConvertFrom(context, sourceType); 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     if (destinationType == typeof(string)) 
     { 
     return true; 
     } 
     return base.CanConvertTo(context, destinationType); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
    { 
     if (value is string)   
     { 
     TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
     T inner = converter.ConvertTo(value, destinationType); 
     return new Wrapper<T>(inner); 
     } 
     return base.ConvertFrom(context, culture, value); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType == typeof(System.String)) 
     { 
     Wrapper<T> wrapper = value as Wrapper<T>(); 
     TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
     return converter.ConvertTo(wrapper.Value, destinationType); 
     } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 
} 

Il problema arriva che non si può avere un generico in questa linea, è annullato:

[TypeConverter(typeof(WrapperConverter<T>))] 
public class Wrapper<T> 

Il mio prossimo approccio è stato quello di cercare di definire un unico convertitore, non generico in grado di gestire eventuali Wrapper<T> istanze. Il mix di entrambi i riflessi e generici mi ha lasciato perplesso su come implementare sia i metodi ConvertTo e ConvertFrom.

Così, per esempio, il mio ConvertTo assomiglia a questo:

public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
{ 
    if (destinationType == typeof(System.String)   
     && value.GetType().IsGenericType) 
    { 

     // 1. How do I enforce that value is a Wrapper<T> instance? 

     Type innerType = value.GetType().GetGenericArguments()[0]; 

     TypeConverter converter = TypeDescriptor.GetConverter(innerType); 

     // 2. How do I get to the T Value property? Introduce an interface that Wrapper<T> implements maybe? 
     object innerValue = ??? 

     return converter.ConvertTo(innerValue, destinationType); 


    } 
    return base.ConvertTo(context, culture, value, destinationType); 
} 

In ConvertFrom ho il più grande problema perché non ho modo di sapere quale classe wrapper per convertire le stringhe incomming in.

Ho creato diversi tipi di custome e TypeConverters da utilizzare con il framework API Web ASP.NET 4, ed è qui che devo utilizzarlo.

Un'altra cosa che ho provato è stata quella di assegnare la mia versione generica del convertitore in fase di esecuzione come visto here, ma il framework WebAPI non l'ha rispettato (cioè, il convertitore non è mai stato creato).

Un'ultima nota, sto usando .NET 4.0 e VS 2010.

+0

Ho già risolto questo problema, credo di aver usato la dinamica per lanciare la T e anche per usare typeof. Dovrei poter pubblicare la mia soluzione domani, poiché non ho il codice accessibile in questo momento. – awright18

+0

http://stackoverflow.com/questions/557340/c-sharp-generic-list-t-how-to-get-the-type-of-t Questo aiuta? – awright18

+0

@ awright18 Grazie, ma non avevo quello di cui avevo bisogno. La mia domanda è principalmente come creare e associare un TypeConverter per un tipo generico. – tcarvin

risposta

28

ho risolto questo con la creazione di un unico convertitore che potrebbe hanlde tutti i tipi di derrived dalla mia classe generica. Il grosso problema di conoscere l'argomento generico T all'interno di ConvertFrom è stato risolto acquisendo le informazioni nel costruttore come mostrato di seguito.

public MyGenericConverter(Type type) 
{ 
    if (type.IsGenericType 
     && type.GetGenericTypeDefinition() == typeof(MyGenericClass<>) 
     && type.GetGenericArguments().Length == 1) 
    { 
     _genericInstanceType = type; 
     _innerType = type.GetGenericArguments()[0]; 
     _innerTypeConverter = TypeDescriptor.GetConverter(_innerType);    
    } 
    else 
    { 
     throw new ArgumentException("Incompatible type", "type"); 
    } 
} 

Ci sono voluti anni per scoprire che l'infrastruttura .NET chiama questo sovraccarico del costruttore se è definito. Non faceva parte della classe TypeConverter documentata.

Spero che tutto questo aiuti il ​​prossimo.

+3

Bello! Grazie per il consiglio. Risolto il mio problema anche dove non pensavo di poter conoscere in modo definitivo il tipo di bersaglio. Sebbene presumibilmente, se non documentato, potrebbe essere soggetto a future rotture. –

+0

Non sembra funzionare più? (.NET 4.5) –

+0

Hmmm, darò un'occhiata. Quel progetto è ancora in 4.0 quindi non posso confermare se funziona solo in quella versione o no. – tcarvin

Problemi correlati