207 votes

Existe-t-il un constructeur générique avec contrainte de paramètre en C #?

En C #, vous pouvez imposer une contrainte à une méthode générique telle que:

 public class A {

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

}
 

Existe-t-il également un moyen de définir une contrainte du type "il existe un constructeur avec un paramètre float [,]?" Le code suivant ne compile pas bien:

 public class A {

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

}
 

Ou y a-t-il une solution de rechange?

170voto

Tim Robinson Points 28696

Comme vous l'avez découvert, vous ne pouvez pas faire cela.

En guise de solution de contournement, je fournis normalement un délégué pouvant créer des objets de type T :

 public class A {

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

}
 

59voto

xpress Points 101

En utilisant la réflexion pour créer un objet générique, le type a toujours besoin du constructeur annulé correct ou une exception sera levée. Vous pouvez transmettre n'importe quel argument tant qu'il correspond à l'un des constructeurs.

De cette manière, vous ne pouvez pas imposer de contrainte au constructeur dans le modèle. Si le constructeur est manquant, une exception doit être gérée au moment de l'exécution plutôt qu'une erreur lors de la compilation.

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

48voto

JaredPar Points 333733

Il n'y a pas une telle construction. Vous pouvez uniquement spécifier une contrainte de constructeur vide.

Je travaille autour de ce problème avec les méthodes lambda.

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

Cas d'utilisation

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

19voto

Sahuagin Points 3209

Voici une solution de contournement pour ce que je trouve personnellement assez efficace. Si vous pensez à ce que un générique constructeur paramétré contrainte, c'est vraiment une correspondance entre les types et les constructeurs avec une signature. Vous pouvez créer votre propre cette cartographie à l'aide d'un dictionnaire. Mettez-les dans un statique de la "fabrique" de la classe et vous pouvez créer des objets de type variable sans avoir à se préoccuper de la construction d'un constructeur lambda à chaque fois:

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

puis dans votre méthode générique, par exemple:

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

9voto

Sean Reilly Points 9869

Non. Pour le moment, la seule contrainte de constructeur que vous pouvez spécifier concerne un constructeur sans argument.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X