Comment créer une classe générique à partir d’une chaîne en C #?

J’ai un cours générique comme ça:

public class Repository {...} 

Et je dois par exemple avec une chaîne … Exemple:

 ssortingng _sample = "TypeRepository"; var _rep = new Repository(); 

Comment puis je faire ça? Est-ce que c’est possible?

Merci!

Voici mes 2 cents:

 Type genericType = typeof(Repository<>); Type[] typeArgs = { Type.GetType("TypeRepository") }; Type repositoryType = genericType.MakeGenericType(typeArgs); object repository = Activator.CreateInstance(repositoryType); 

Répondre à la question en commentaire.

 MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething"); MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something)); closedMethod.Invoke(repository, new[] { "Query Ssortingng" }); 

Commencez par récupérer l’object Type à l’aide de Type.GetType(ssortingngContainingTheGenericTypeArgument)

Ensuite, utilisez typeof(Repository<>).MakeGenericType(theTypeObject) pour obtenir un type générique.

Et enfin, utilisez Activator.CreateInstance

C’est un travail pour le mot-clé dynamic venir en C # 4.0.

Il y a quelques bonnes astuces ici qui vous donneront une instance de votre object, mais peu importe ce que la version actuelle de C # saura seulement qu’elle a un object , et elle ne peut pas faire grand chose avec un object tout seul, car le C # actuel ne le permet pas. soutenir la liaison tardive. Vous devez au moins pouvoir utiliser un type connu pour tout faire avec. En fin de compte, vous devez connaître le type dont vous avez besoin au moment de la compilation ou vous n’êtes pas chanceux.

Maintenant, si vous pouvez contraindre votre classe de référentiel à des types implémentant une interface connue, vous êtes dans une bien meilleure forme.

Si je comprends bien votre question … Ce que vous essayez de faire est de prendre votre type (Repository ) et de construire une implémentation générique spécifique de celle-ci au moment de l’exécution.

Si c’est le cas, jetez un coup d’œil à MakeGenericType . Vous pouvez utiliser typeof (Repository) et le System.Type de l’object que vous voulez pour T et le construire de cette façon. Une fois que vous avez le type, Activator.CreateInstance fonctionnera pour vous.

En supposant que votre chaîne contienne le nom d’un type, vous pouvez écrire

 object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample))); 

Cependant, _rep sera un object non typé et vous ne pourrez rien faire avec. Comme vous ne savez pas quel type de classe générique est au moment de la compilation, vous ne la transcrivez pas. (Sauf si le référentiel hérite d’une classe non générique ou implémente une interface non générique)

Vous pouvez résoudre ce problème en créant une classe de base non générique pour Repository et en lui lançant l’object.

Cependant, selon votre situation, vous souhaiterez probablement faire de Repository une classe non générique.

Si Repository est une classe contenant d’autres classes, il est probablement préférable de la rendre non générique. Vous pouvez faire en sorte que son constructeur prenne un object Type , puis appelez Type.IsInstanceOfType sur chaque object que vous ajoutez pour vous assurer qu’il s’agit du bon type.

Si Repository est une collection d’éléments catégorisée, il est probablement préférable de le rendre non générique et de faire en sorte que son constructeur prenne une ssortingng category .

Si vous souhaitez des conseils plus spécifiques, merci de poster plus de détails sur votre situation.

 Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String")); object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName); 

Cela créerait une instance de Repository . Vous pouvez remplacer “System.Ssortingng” par le type de votre choix.

Les génériques fonctionnent sur des types, pas sur des instances. Vous pouvez en lire plus ici .

On dirait que vous devez simplement append à votre classe un constructeur qui prend le type souhaité et initialise la valeur:

 public class Foo { private T = default(T); public Foo(T initValue) { _val = T; } } 

C’est “en quelque sorte” possible. En quelque sorte, vous pouvez le faire, mais c’est un peu un bidouillage.

Vous avez 3 options:

Si vous connaissez vos classes à l’avance, utilisez une instruction switch. Fondamentalement, comme ceci:

 switch(str){ case "TypeRepository": return new Repository; } 

En tant que forme plus avancée de ce qui précède, vous pouvez utiliser un dictionnaire au lieu d’une table de hachage.

 var factory = new Dictionary>(); factory.Add( "TypeRepository", () => new Repository() ); var theObject = factory["TypeRepository"]() as Repository; 

Pour une plus grande flexibilité, vous pouvez utiliser la reflection pour faire correspondre les chaînes aux classes lors de l’exécution. Sachez que la reflection est assez lente, donc si vous faites cela régulièrement, vous voulez l’éviter. Par exemple, en voici une qui utilise la méthode de Frans Bouma . Il suffit de changer la List<> en Repository<> dans votre code:

 public static object MakeList( ssortingng typeStr ) { var nameSpace = "MyTestApplication" + "."; var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED var listType = typeof(List<>).MakeGenericType(objType); return Activator.CreateInstance(listType); } var listOfThings = MakeList("MyCoolObject") as List; 

Remarque: Il est impossible d’éviter le fait que tous ces mécanismes renvoient un object , que vous devez alors transtyper vers votre type approprié, plutôt que de simplement renvoyer des valeurs fortement typées.

Ceci est inévitable, car vous ne connaissez pas le type de la liste jusqu’à l’exécution, et C # est construit autour de la connaissance de la compilation (c’est ce que les gens veulent dire quand ils parlent de “langage de programmation statiquement typé”). Ce sera moins pénible en C # 4, où vous pourrez revenir en dynamic , ce qui vous épargnera le casting.

Le “T” dans une classe générique représente un type, pas une instance d’un type. Donc, si vous voulez que votre référentiel contienne des objects chaîne, utilisez

 var _rep = new Repository();