10

Ich mag würde eine TypeConverter für eine generische Klasse erstellen, wie folgt aus:kann kein Typeconverter für eine generische Art erstellen

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

Das Problem kommt, dass kein generisch in dieser Linie haben kann, ist es nicht zulässig:

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

Mein war nächster Ansatz zu versuchen, einen einzigen, nicht-generic-Konverter zu definieren, die alle Wrapper<T> Instanzen umgehen konnten. Die Mischung aus Reflexion und Generika hat mich ratlos darüber, wie beide die ConvertTo und ConvertFrom Methoden zu implementieren.

So zum Beispiel, sieht meine ConvertTo wie folgt aus:

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 ich das größte Problem, weil ich keine Möglichkeit haben, zu wissen, welche Wrapper-Klasse in die incomming Strings zu konvertieren.

Ich habe mehrere custome Typen und TypeConverter für die Verwendung mit dem ASP.NET 4 Web API Framework erstellt, und das ist, wo ich dies auch verwendet werden muss.

Eine andere Sache, die ich versuchte war, meine generische Version des Konverters zur Laufzeit wie gesehen here, aber das WebAPI-Framework nicht respektieren (was bedeutet, der Konverter wurde nie erstellt).

Eine letzte Anmerkung, ich bin mit .NET 4.0 und VS 2010

+0

Ich habe dieses Problem vorher gelöst, ich glaube, ich habe dynamisch verwendet, um das T zu werfen und typeof auch verwendet. Ich sollte morgen meine Lösung posten können, da ich den Code in diesem Moment nicht zugänglich habe. – awright18

+0

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

+0

@ awright18 Danke, aber ich hatte nicht, was ich brauchte. Meine Frage ist meistens wie man einen TypeConverter für einen generischen Typ erstellt und assoziiert. – tcarvin

Antwort

28

Ich löste dies durch einen einzigen Converter erstellen, die alle Typen schließt man aus meiner generische Klasse hanlde könnte. Das große Problem, das generische arg T innerhalb des ConvertFrom zu kennen, wurde gelöst, indem man die Informationen im Konstruktor wie unten gesehen abfing.

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

Es dauerte Jahre, bis ich entdeckte, dass die .NET-Infrastruktur diese Konstruktorüberladung reflektiv nennt, wenn sie definiert ist. Es war nicht Teil der dokumentierten TypeConverter-Klasse.

Hoffe, das alles hilft dem nächsten Kerl.

+3

Schön! Danke für den Tipp. Löst auch mein Problem, wo ich nicht glaubte, den Zieltyp abschließend zu kennen. Obwohl vermutlich, wenn nicht dokumentiert, können zukünftige Brüche unterliegen. –

+0

Scheint nicht mehr zu funktionieren? (.NET 4.5) –

+0

Hmmm, ich werde es mir ansehen. Dieses Projekt ist immer noch in 4.0, daher kann ich nicht bestätigen, ob es nur in dieser Version funktioniert oder nicht. – tcarvin

Verwandte Themen