2009-12-05 14 views
123

In C# si può mettere un vincolo su un metodo generico come:Esiste un costruttore generico con limitazione di parametro in C#?

public class A { 

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

} 

cui si specifica che T dovrebbe avere un costruttore che non richiede parametri. Mi chiedo se c'è un modo per aggiungere un vincolo come

Il seguente codice non viene compilato "esiste un costruttore con un parametro float[,]?":

public class A { 

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

} 

Una soluzione è anche utile?

+0

possibile duplicato di [Come per vincolare tipo generico a deve avere un construtor che prende alcuni parametri?] (Http://stackoverflow.com/questions/853703/how-to-constrain-generic-type-to -must-have-a-construtor-that-takes-certain-param) – nawfal

risposta

115

Come hai trovato, non si può fare questo.

Come una soluzione che normalmente forniscono un delegato che può creare oggetti di tipo T:

public class A { 

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

} 
+37

i vincoli dei costruttori parametrizzati sono assenti per un motivo logico o è solo qualcosa che deve essere ancora aggiunto alla lingua? –

+18

concordato ...dovremmo avere 'new (float, double)', 'new (stringa)', ecc. – SliverNinja

+8

@Sahuagin Penso che non sia possibile farlo perché quando si eredita da una classe, non c'è alcuna garanzia che la sottoclasse abbia quella costruttore è definito, in quanto i costruttori non sono ereditati. Tuttavia, ogni classe ha un costruttore di parametri vuoto. – Matthew

5

No. Al momento l'unico vincolo di costruzione che è possibile specificare è per un costruttore no-arg.

39

Non esiste un tale costrutto. È possibile specificare solo un vincolo di costruttore vuoto.

Io lavoro su questo problema con i metodi lambda.

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

Use Case

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

Non c'è modo di astrarre la creazione di 'Foo' all'interno del' Metodo'? –

+0

Cosa succede se l'utente del 'Metodo' fa' Metodo (x => new Foo()); '? Esiste comunque la certezza che il lambda debba essere così? –

15

Ecco una soluzione per questo che io personalmente trovo molto efficace. Se si pensa a cosa sia un vincolo di costruttore parametrico generico, si tratta in realtà di una mappatura tra tipi e costruttori con una firma particolare. È possibile creare la propria mappatura utilizzando un dizionario. Mettere questi in una "fabbrica" ​​di classe statica e si possono creare oggetti di tipo variabile, senza doversi preoccupare di costruire una lambda costruttore ogni volta:

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

poi nel vostro metodo generico, per esempio:

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

perché questo merita un down down? funziona molto bene nella mia esperienza. –

+1

Lo sto usando ora, penso che sia un buon modello. Funziona davvero bene con il modello Factory. Grazie! – Matthew

32

Utilizzando la riflessione per creare un oggetto generico, il tipo richiede comunque il costruttore corretto dichiarato o verrà generata un'eccezione. Puoi passare qualsiasi argomento purché corrispondano a uno dei costruttori.

Utilizzato in questo modo non è possibile applicare un vincolo al costruttore nel modello. Se il costruttore manca, è necessario gestire un'eccezione in fase di esecuzione piuttosto che ottenere un errore in fase di compilazione.

// 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); 
Problemi correlati