Délègue aux opérations génériques où le type générique est inconnu. Comment créer quelque chose comme ça?

Supposons que j’ai le code suivant.

static class Store { public static TA; public static TB; public static TC; } public static class Store { public static Value A = new Value((v) => Store.A = v); //just an example of what I want public static Value B = new Value((v) => Store.B = v); //just an example of what I want public static Value C = new Value(SetC); //just an example of what I want public static void SetA(T value) { Store.A = value; } public static void SetB(T value) { Store.B = value; } public static void SetC(T value) { Store.C = value; } } public class Value { Action _valueChanger; //just an example of what I want public Value(Action valueChanger) { //just an example of what I want _valueChanger = valueChanger; } public void SetValue (T value) { _valueChanger(value); //just an example of what I want } } 

Je souhaite écrire Store.A.SetValue(42) afin que la valeur soit enregistrée dans Store.A . Que puis-je écrire au lieu des lignes marquées par “juste un exemple de ce que je veux” pour que cela se produise? (Je souhaite explorer une solution ne comportant pas de dictionnaires ou quelque chose de similaire)

Reformuler la question: je souhaite modifier la classe Value (définir des champs, écrire un constructeur et écrire la méthode Value.SetValue (valeur T)), puis construire trois variables différentes de type Value (A, B, C) de cette manière. que lorsque j’appelle Store.A.SetValue(42) la valeur Store.A devient 42.

Une autre variante des cours:

 static class Holder { T Value { get; set; } } static class Store2 { public static Holder A = new Holder(); public static Holder B = new Holder(); public static Holder C = new Holder(); } public static class Store2 { public static Value A = new Value2(Store2.A); //just an example of what I want public static Value B = new Value2(Store2.B); //passing non-specific generic expression public static Value C = new Value3({TFree}() => Store2.C); //just an example of what I want } public class Value2 { //Non-generic class! Holder{TFree} _holder; //just an example of what I want public Value(Holder{TFree} holder) { //just an example of what I want _holder = holder; } public void SetValue (T value) { _holder{T}.Value = value; //just an example of what I want } } public class Value3 { //Non-generic class! (Another variation) Func{TFree}<Holder> _holderFactory; //just an example of what I want public Value(Func{TFree}<Holder> holderFactory) { //just an example of what I want _holderFactory = holderFactory; } public void SetValue (T value) { Holder holder = _holderFactory{T}(); //just an example of what I want holder.Value = value; } } 

Solution: Une solution simple, sans reflection ni collection, a été trouvée en utilisant les réponses à une autre question ( émulation de delegates avec des parameters de type générique libre en C # et émulation de delegates avec des parameters de type générique libre en C # ). La solution est Délégués aux opérations génériques où le type générique est inconnu. Comment créer quelque chose comme ça? .

Utiliser un tableau pour stocker les valeurs et y accéder via une propriété à l’aide d’un index

 public static class Store { public static readonly T[] Values = new T[3]; public static TA { get { return Values[0]; } set { Values[0] = value; } } public static TB { get { return Values[1]; } set { Values[1] = value; } } public static TC { get { return Values[2]; } set { Values[2] = value; } } } public static class Store { public static readonly Value A = new Value(0); public static readonly Value B = new Value(1); public static readonly Value C = new Value(2); } public class Value { private int _index; public Value(int index) { _index = index; } public void SetValue(T value) { Store.Values[_index] = value; } public T GetValue() { return Store.Values[_index]; } } 

Étant donné que le constructeur de Value ne connaît aucun paramètre de type générique, vous ne pouvez avoir aucune référence à un Store spécifique Store .


METTRE À JOUR

Sachez qu’une copie de Store sera créée pour chaque argument de type distinct que vous avez fourni pour T Voir cet exemple

 Store.A.SetValue(42); Store.A.SetValue("Douglas Adams"); Store.A.SetValue(new DirectoryInfo(@"C:\")); Store.A.SetValue(new List()); var x1 = Store.A.GetValue(); // --> 42 var x2 = Store.A.GetValue(); // --> "Douglas Adams" var x3 = Store.A.GetValue(); // --> DirectoryInfo{ C:\ } var x4 = Store.A.GetValue>(); // --> List{ Count = 0 } 

En utilisant le débogueur, vous verrez que quatre valeurs différentes sont stockées dans A en même temps! Ce sont quatre A's différents qui existent dans quatre Store .

Le problème s’est avéré être résolu. Mike-z m’a donné une solution presque parfaite pour le problème de la méthode délégate à générique ( émulation de delegates avec des parameters de type générique libre en C # ), que j’ai modifiée pour être une solution complète: ( émulation de delegates avec des parameters de type générique libre en C # ). .

La solution à cette question devient facile aussi. Les interfaces peuvent contenir des méthodes génériques et nous pouvons utiliser les variables à valeur d’interface pour stocker des liens vers des méthodes génériques sans spécifier d’arguments de type concret. Le code suivant utilise la classe Store sans modifications et utilise l’interface BSetter et les “fermetures” ASetter / BSetter / CSetter pour contenir des références à différents membres génériques. La classe Value stocke les références dans une variable de ISetter ISetter et utilise le membre générique auquel le _setter lié une fois que l’argument de type T devient disponible.

 public interface ISetter { void SetValue(T value); } public static class Store { public static Value A = new Value(new ASetter()); public static Value B = new Value(new BSetter()); public static Value C = new Value(new CSetter()); class ASetter : ISetter { public void SetValue(T value) { Store.A = value; } } class BSetter : ISetter { public void SetValue(T value) { Store.B = value; } } class CSetter : ISetter { public void SetValue(T value) { Store.C = value; } } } public class Value { ISetter _setter; public Value(ISetter setter) { _setter = setter; } public void SetValue (T value) { _setter.SetValue(value); } }