Je cherche un moyen d'avoir une fonction telle que:
myFunction({"Key", value}, {"Key2", value});
Je suis sûr qu'il y a quelque chose avec des types anonymes qui serait assez facile, mais je ne le vois pas.
La seule solution à laquelle je peux penser est d'avoir un paramètre "params KeyValuePair [] pairs", mais cela finit par être quelque chose de similaire à:
myFunction(new KeyValuePair<String, object>("Key", value), new KeyValuePair<String, object>("Key2", value));
Ce qui est, certes, beaucoup plus laid.
MODIFIER:
Pour clarifier, j'écris une classe "Message" pour passer de 2 systèmes différents. Il contient un court-courrier spécifiant le type de message et un dictionnaire de chaîne à objecter pour "Données" associé au message. J'aimerais pouvoir transmettre toutes ces informations au constructeur, je peux donc le faire:
Agent.SendMessage (nouveau message (MessageTypes.SomethingHappened, "A", x, "B", y, "C", z)); ou une syntaxe similaire.
Lorsque la syntaxe est mauvaise pour un modèle par ailleurs décent, modifiez-la. Que diriez-vous:
public void MyFunction(params KeyValuePair<string, object>[] pairs)
{
// ...
}
public static class Pairing
{
public static KeyValuePair<string, object> Of(string key, object value)
{
return new KeyValuePair<string, object>(key, value);
}
}
Usage:
MyFunction(Pairing.Of("Key1", 5), Pairing.Of("Key2", someObject));
Encore plus intéressant serait d’ajouter une méthode d’extension à string
pour la rendre pairable:
public static KeyValuePair<string, object> PairedWith(this string key, object value)
{
return new KeyValuePair<string, object>(key, value);
}
Usage:
MyFunction("Key1".PairedWith(5), "Key2".PairedWith(someObject));
Modifier : Vous pouvez également utiliser la syntaxe du dictionnaire sans crochets génériques en dérivant de Dictionary<,>
:
public void MyFunction(MessageArgs args)
{
// ...
}
public class MessageArgs : Dictionary<string, object>
{}
Usage:
MyFunction(new MessageArgs { { "Key1", 5 }, { "Key2", someObject } });
Drôle, je viens de créer (il y a quelques minutes) une méthode qui permet de le faire, en utilisant des types anonymes et des réflexions:
MyMethod(new { Key1 = "value1", Key2 = "value2" });
public void MyMethod(object keyValuePairs)
{
var dic = DictionaryFromAnonymousObject(keyValuePairs);
// Do something with the dictionary
}
public static IDictionary<string, string> DictionaryFromAnonymousObject(object o)
{
IDictionary<string, string> dic = new Dictionary<string, string>();
var properties = o.GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
dic.Add(prop.Name, prop.GetValue(o, null) as string);
}
return dic;
}
Un hack, mais vous pourriez avoir votre classe Message
implémenter l'interface IEnumerable
et lui donner une méthode Add
. Vous pourrez ensuite utiliser la syntaxe d'initialisation de la collection:
Agent.SendMessage
(
new Message(MessageTypes.SomethingHappened) {{ "foo", 42 }, { "bar", 123 }}
);
// ...
public class Message : IEnumerable
{
private Dictionary<string, object> _map = new Dictionary<string, object>();
public Message(MessageTypes mt)
{
// ...
}
public void Add(string key, object value)
{
_map.Add(key, value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_map).GetEnumerator();
// or throw a NotImplementedException if you prefer
}
}
Depuis C # 7.0, vous pouvez utiliser des tuples de valeur. C # 7.0 introduit non seulement un nouveau type, mais une syntaxe simplifiée pour les types Tuple ainsi que pour les valeurs Tuple.
public static void MyFunction(params (string Key, object Value)[] pairs)
{
foreach (var pair in pairs) {
Console.WriteLine($"{pair.Key} = {pair.Value}");
}
}
Il est également possible de déconstruire un tuple comme celui-ci
var (key, value) = pair;
Console.WriteLine($"{key} = {value}");
Ceci extrait les éléments du tuple dans deux variables distinctes key
et value
.
Maintenant, vous pouvez facilement appeler MyFunction
avec un nombre variable d'arguments:
MyFunction(("a", 1), ("b", 2), ("c", 3));
Utiliser un dictionnaire:
myFunction(new Dictionary<string, object>(){
{"Key", value},
{"Key2", value}});
Ce qui est simple, vous n'avez besoin que d'un new Dictionary<K, V>
, pas pour chaque argument. C'est trivial pour obtenir les clés et les valeurs.
Ou avec un type anonyme:
myFunction(new {
Key = value,
Key2 = value});
Ce qui n’est pas très agréable à utiliser dans la fonction, vous aurez besoin de réflexion. Cela ressemblerait à quelque chose comme ça:
foreach (PropertyInfo property in arg.GetType().GetProperties())
{
key = property.Name;
value = property.GetValue(arg, null);
}
(Stupide de ma tête, probablement quelques erreurs ...)
Utilisez un dictionnaire ...
void Main()
{
var dic = new Dictionary<string, object>();
dic.Add( "Key1", 1 );
dic.Add( "Key2", 2 );
MyFunction( dic ).Dump();
}
public static object MyFunction( IDictionary dic )
{
return dic["Key1"];
}
Voici plus de la même chose:
static void Main(string[] args)
{
// http://msdn.Microsoft.com/en-us/library/bb531208.aspx
MyMethod(new Dictionary<string,string>()
{
{"key1","value1"},
{"key2","value2"}
});
}
static void MyMethod(Dictionary<string, string> dictionary)
{
foreach (string key in dictionary.Keys)
{
Console.WriteLine("{0} - {1}", key, dictionary[key]);
}
}
Vous trouverez quelques détails sur l’initialisation d’un dictionnaire ici .
Avec type dynamique en C # 4.0:
public class MyClass
{
// Could use another generic type if preferred
private readonly Dictionary<string, dynamic> _dictionary = new Dictionary<string, dynamic>();
public void MyFunction(params dynamic[] kvps)
{
foreach (dynamic kvp in kvps)
_dictionary.Add(kvp.Key, kvp.Value);
}
}
Appeler en utilisant:
MyFunction(new {Key = "Key1", Value = "Value1"}, new {Key = "Key2", Value = "Value2"});
Vous pouvez le faire:
TestNamedMethod(DateField => DateTime.Now, IdField => 3);
où DateField et IdField sont supposés être un identifiant 'chaîne'.
Le TestNameMethod:
public static string TestNameMethod(params Func<object, object>[] args)
{
var name = (args[0].Method.GetParameters()[0]).Name;
var val = args[0].Invoke(null);
var name2 = (args[1].Method.GetParameters()[0]).Name;
var val2 = args[1].Invoke(null);
Console.WriteLine("{0} : {1}, {2} : {3}", name, val, name2, val2);
}
Les performances sont 5% plus rapides que l'utilisation de Dictionnaire. Inconvénient: vous ne pouvez pas utiliser la variable comme clé.
Vous pouvez utiliser Tuples pour obtenir quelque chose de similaire au Pairing.Of
de @Bryan Watts sans la classe supplémentaire:
public static void MyFunction(params Tuple<string, int>[] pairs)
{
}
MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));
Vous pouvez également référencer le nugetpackage "valuetuple", qui permet d'effectuer les opérations suivantes:
public static void MyFunction(params ValueTuple<string, object>[] pairs)
{
var pair = pairs[1];
var stringValue = pair.item1;
var objectValue = pair.item2;
}
Vous pouvez alors appeler la méthode comme ceci:
MyFunction(("string",object),("string", object));