2016-06-05 9 views
0

Ich habe separate Implementierungen einer generischen Schnittstelle (eine für Klassen, eine für Strukturen) und ich möchte eine statische Create-Methode verwenden, die Konstruktion behandelt. Aber ich kann nicht herausfinden, wie man den Compiler dazu bringt, mir bezüglich der korrekten Typabhängigkeit zu vertrauen. Ich verstehe, warum es nicht funktioniert, aber wie komme ich damit klar?Konstruieren von generischen Typen ohne die class/struct-Einschränkung

public interface ISomething<T> { } 

internal class SomethingForReferenceTypes<T> 
    : ISomething<T> where T : class { } 

internal class SomethingForValueTypes<T> 
    : ISomething<T> where T : struct { } 

public static class Something 
{ 
    public static ISomething<T> Create<T>() 
    { 
    bool TIsAReferenceType = IKnowHowToFigureThisOut(); 
    if (TIsAReferenceType) 
     return new SomethingForReferenceTypes<T>(); // ← T is not accepted here. 
    else 
     return new SomethingForValueTypes<T>(); // ← T is not accepted here. 
    } 
} 
+0

sieht aus wie Sie Reflektion verwenden müssen, um die generischen Typen zu machen und sie dann zu aktivieren – Nkosi

Antwort

3

Ich glaube nicht, dass Sie diese in der Lage sein werden direkt zu tun, aber man konnte leicht Reflexion zum Erstellen der Instanz:

Type openType = TIsAReferenceType 
    ? typeof(SomethingForReferenceTypes<>) 
    : typeof(SomethingForValueTypes<>); 
Type constructedType = openType.MakeGenericType(typeof(T)); 
object ret = Activator.CreateInstance(constructedType); 
return (ISomething<T>) ret; 
+0

Würde sich der Compiler nicht beschweren über die Verwendung von 'T' mit den Klassen ähnlich dem Fehler, der ursprünglich erhalten wurde? – Nkosi

+0

@ Nkosi, yup, tut es. –

+0

@ Nkosi: Ooh, sehr wahrscheinlich. Do. Wird es reparieren. –

1

Kurze Antwort ist, können Sie nicht . Sie können dies tun, mit Reflexion, aber für maximale Effizienz werden Sie brauchen eine dynamische Dispatch für die statische Create-Methode auszuführen:

public static class Something<T> 
{ 
    public static readonly Func<ISomething<T>> Create; 
    static Something() 
    { 
     var name = typeof(T).IsValueType ? "ValueType" : "Reference"; 
     var method = typeof(Something<T>).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static) 
             .MakeGenericMethod(typeof(T)); 
     Create = (Func<ISomething<T>>)Delegate.CreateDelegate(typeof(Func<ISomething<T>>), null, method); 
    } 

    static ISomething<T0> Reference<T0>() 
     where T0 : class 
    { 
     return new SomethingForReferenceTypes<T0>(); 
    } 
    static ISomething<T0> ValueType<T0>() 
     where T0 : struct 
    { 
     return new SomethingForValueTypes<T0>(); 
    } 
} 

Dann können Sie es mit jedem T, über Something<T>.Create() aufrufen. Sollte viel effizienter sein als Activator.CreateInstance.

+0

Interessanter Ansatz mit der Statik, könnte es in der Tat wiederholte Aufrufe beschleunigen. –

Verwandte Themen