2009-12-05 8 views
123

In C# können Sie eine Einschränkung für eine generische Methode wie gesagt:Gibt es einen generischen Konstruktor mit Parameterbeschränkung in C#?

public class A { 

    public static void Method<T> (T a) where T : new() { 
     //...do something... 
    } 

} 

Wo Sie angeben, dass T einen Konstruktor haben sollte, die keine Parameter erfordert. Ich frage mich, ob es einen Weg gibt eine Einschränkung hinzuzufügen, wie

Der folgende Code nicht kompiliert „es einen Konstruktor mit einem float[,] Parameter existiert?“:

public class A { 

    public static void Method<T> (T a) where T : new(float[,] u) { 
     //...do something... 
    } 

} 

Eine Abhilfe ist auch sinnvoll?

+0

möglich Duplikat von [Wie generische Art beschränken zu müssen construtor haben, die bestimmte Parameter verwendet?] (Http://stackoverflow.com/questions/853703/how-to-constrain-generic-type-to -must-have-a-construtor-das-nimmt-bestimmte-param) – nawfal

Antwort

115

Wie Sie gefunden haben, können Sie dies nicht tun.

Zur Umgehung des Problems liefern ich normalerweise einen Delegaten, T Objekte vom Typ erstellen:

public class A { 

    public static void Method<T> (T a, Func<float[,], T> creator) { 
     //...do something... 
    } 

} 
+37

sind parametrisierte Constructor-Constraints aus einem logischen Grund nicht vorhanden, oder ist es nur etwas, das der Sprache noch hinzugefügt werden muss? –

+18

Einverstanden ...Wir sollten 'new (float, double)', 'new (string)' usw. haben. – SliverNinja

+8

@Sahuagin Ich denke, es ist nicht möglich, weil, wenn Sie von einer Klasse erben, gibt es keine Garantie, dass die Unterklasse das hat Konstruktor ist definiert, da Konstruktoren nicht vererbt werden. Jede Klasse hat jedoch einen leeren Parameterkonstruktor. – Matthew

5

Nein. Im Moment ist die einzige Konstruktoreinschränkung, die Sie angeben können, für einen Konstruktor ohne Argon.

39

Es gibt kein solches Konstrukt. Sie können nur eine leere Konstruktoreinschränkung angeben.

Ich arbeite dieses Problem mit Lambda-Methoden.

public static void Method<T>(Func<int,T> del) { 
    var t = del(42); 
} 

Use Case

Method(x => new Foo(x)); 
+0

Es gibt keine Möglichkeit, die Erstellung von 'Foo' innerhalb der' Methode' zu ​​abstrahieren? –

+0

Was passiert, wenn der Benutzer der 'Methode' 'Methode (x => new Foo());'? Gibt es sowieso, um sicherzustellen, dass das Lambda so sein sollte? –

15

Hier ist eine Abhilfe für dieses, die ich persönlich sehr effektiv finden. Wenn Sie daran denken, was eine generische parametrisierte Constructor-Constraint ist, ist es wirklich eine Zuordnung zwischen Typen und Konstruktoren mit einer bestimmten Signatur. Sie können Ihr eigenes Mapping mit einem Wörterbuch erstellen. Legen Sie diese in einer statischen „Fabrik“ Klasse und Sie können Objekte unterschiedliche Art erstellen, ohne jedes Mal über den Aufbau ein Konstruktor Lambda zu kümmern:

public static class BaseTypeFactory 
{ 
    private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2); 

    private static readonly Dictionary<Type, BaseTypeConstructor> 
    mTypeConstructors = new Dictionary<Type, BaseTypeConstructor> 
    { 
     { typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) }, 
     { typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) }, 
     { typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) } 
    }; 

dann in Ihrer generischen Methode, zum Beispiel:

public static T BuildBaseType<T>(...) 
     where T : BaseType 
    { 
     ... 
     T myObject = (T)mTypeConstructors[typeof(T)](value1, value2); 
     ... 
     return myObject; 
    } 
+1

Warum verdient dies einen down thumb? Es funktioniert sehr gut in meiner Erfahrung. –

+1

Ich benutze das jetzt, ich denke, es ist ein gutes Muster. Funktioniert sehr gut mit dem Factory-Muster. Vielen Dank! – Matthew

32

Wenn Sie mit reflection ein generisches Objekt erstellen, muss der Typ immer noch den korrekten Konstruktor deklariert haben oder eine Ausnahme wird ausgelöst. Sie können jedes Argument übergeben, solange sie mit einem der Konstruktoren übereinstimmen.

Auf diese Weise können Sie dem Konstruktor in der Vorlage keine Einschränkung auferlegen. Wenn der Konstruktor fehlt, muss eine Ausnahme zur Laufzeit behandelt werden, anstatt einen Fehler zur Kompilierzeit zu erhalten.

// public static object CreateInstance(Type type, params object[] args); 

// Example 1 
T t = (T)Activator.CreateInstance(typeof(T)); 
// Example 2 
T t = (T)Activator.CreateInstance(typeof(T), arg0, arg1, arg2, ...); 
// Example 3 
T t = (T)Activator.CreateInstance(typeof(T), (string)arg0, (int)arg1, (bool)arg2);