450 votes

Passage d’arguments à c# new() générique de type basé sur un modèle

Je suis en train de créer un nouvel objet de type T via son constructeur lors de l’ajout à la liste.

J’obtiens une erreur de compilation : le message d’erreur est :

' T ' : ne peut pas fournir des arguments lorsque vous créez une instance d’une variable

Mais mes cours ont un argument de constructeur ! Comment puis-je faire ce travail ?

434voto

JaredPar Points 333733

Pour créer une instance d'un type générique dans une fonction, vous devez limiter la "nouvelle" pavillon.

public static string GetAllItems<T>(...) where T : new()

Toutefois, cela ne fonctionne que lorsque vous souhaitez appeler le constructeur qui n'a pas de paramètres. Pas le cas ici. Au lieu de cela, vous aurez à fournir un autre paramètre qui permet la création de l'objet sur la base de paramètres. Le plus simple est une fonction.

public static string GetAllItems<T>(..., Func<ListItem,T> del) {
  ...
  List<T> tabListItems = new List<T>();
  foreach (ListItem listItem in listCollection) 
  {
    tabListItems.Add(del(listItem));
  }
  ...
}

Ensuite, vous pouvez l'appeler comme

GetAllItems<Foo>(..., l => new Foo(l));

359voto

user287107 Points 4383

Vous pouvez utiliser la classe activator :

54voto

James Jones Points 3291

Puisque personne ne pris la peine de poster la réponse « Reflet » (qui, personnellement, je pense est la meilleure réponse), va ici :

Edit : Cette réponse est déconseillée en raison Activator.CreateInstance de .NET 3.5, cependant il est toujours utile dans les anciennes versions de .NET.

33voto

Tim Lehner Points 8122

Objet de l'initialiseur

Si votre constructeur avec le paramètre n'est pas rien faire, en plus de la définition d'une propriété, vous pouvez le faire en C# 3 ou mieux, à l'aide d'un initialiseur d'objet plutôt que d'appeler un constructeur (ce qui est impossible, comme il a été mentionné):

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
   } 
   ...
}

En utilisant cela, vous pouvez toujours mettre toute logique constructeur par défaut (vide) constructeur, trop.

Activateur.CreateInstance()

Alternativement, vous pouvez appeler l'Activateur.CreateInstance() comme ceci:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
        object[] args = new object[] { listItem };
        tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
   } 
   ...
}

Notez que l'Activateur.CreateInstance peut avoir une certaine surcharge de performance que vous voudrez peut-être éviter si la vitesse d'exécution est une priorité absolue et une autre option est facile à gérer pour vous.

20voto

Garry Shutler Points 20898

Cela ne fonctionnera pas dans votre situation. Vous pouvez spécifier uniquement la contrainte qu’il possède un constructeur vide :

Ce que vous pourriez faire, c’est utiliser l’injection de propriété en définissant cette interface :

Ensuite vous pourriez altérer votre méthode pour que ce soit :

L’autre alternative est le `` méthode décrite par JaredPar.

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