wake-up-neo.com

Schlüsselwertpaare in C # -Parametern

Ich suche nach einer Möglichkeit, eine Funktion zu haben, wie zum Beispiel:

myFunction({"Key", value}, {"Key2", value});

Ich bin sicher, es gibt etwas mit anonymen Typen, das wäre ziemlich einfach, aber ich sehe es nicht.

Die einzige Lösung, die ich mir vorstellen kann, ist, einen Parameter "params KeyValuePair [] pair" zu haben, der aber am Ende etwas ähnelt:

myFunction(new KeyValuePair<String, object>("Key", value), new KeyValuePair<String, object>("Key2", value));

Welches ist zugegebenermaßen viel hässlicher.

BEARBEITEN:

Zur Klarstellung schreibe ich eine "Message" -Klasse, um zwischen zwei verschiedenen Systemen zu wechseln. Es enthält eine Ushort, die den Nachrichtentyp angibt, und ein Wörterbuch der Zeichenfolge für "Data", die der Nachricht zugeordnet sind. Ich möchte all diese Informationen im Konstruktor weitergeben können, also kann ich Folgendes tun:

Agent.SendMessage (neue Nachricht (MessageTypes.SomethingHappened, "A", x, "B", y, "C", z)); oder eine ähnliche Syntax.

28
Quantumplation

Wenn die Syntax für ein ansonsten anständiges Muster schlecht ist, ändern Sie die Syntax. Wie wäre es mit:

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

Verwendungszweck:

MyFunction(Pairing.Of("Key1", 5), Pairing.Of("Key2", someObject));

Noch interessanter wäre es, eine Erweiterungsmethode zu string hinzuzufügen, um sie paarweise zu machen:

public static KeyValuePair<string, object> PairedWith(this string key, object value)
{
    return new KeyValuePair<string, object>(key, value);
}

Verwendungszweck:

MyFunction("Key1".PairedWith(5), "Key2".PairedWith(someObject));

Edit : Sie können die Wörterbuchsyntax auch ohne die generischen Klammern verwenden, indem Sie von Dictionary<,> ableiten:

public void MyFunction(MessageArgs args)
{
    // ...
}

public class MessageArgs : Dictionary<string, object>
{}

Verwendungszweck:

MyFunction(new MessageArgs { { "Key1", 5 }, { "Key2", someObject } });
58
Bryan Watts

Witzig, ich habe gerade vor (Minuten) eine Methode erstellt, die dies ermöglicht, indem anonyme Typen und Überlegungen verwendet werden:

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;
}
8
Thomas Levesque

Ein bisschen hacken, aber Sie könnten Ihre Message-Klasse das IEnumerable-Interface implementieren und ihm eine Add-Methode geben. Sie können dann die Syntax für die Initialisierung der Sammlung verwenden:

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
    }
}
7
LukeH

Seit C # 7.0 können Sie Wertetupel verwenden. C # 7.0 führt nicht nur einen neuen Typ ein, sondern auch eine vereinfachte Syntax für Tuple-Typen sowie für Tuple-Werte.

public static void MyFunction(params (string Key, object Value)[] pairs)
{
    foreach (var pair in pairs) {
        Console.WriteLine($"{pair.Key} = {pair.Value}");
    }
}

Es ist auch möglich, ein Tuple auf diese Weise zu dekonstruieren

        var (key, value) = pair;
        Console.WriteLine($"{key} = {value}");

Dadurch werden die Elemente des Tupels in zwei separaten Variablen key und value extrahiert.

Nun können Sie mit variabler Anzahl von Argumenten MyFunction problemlos aufrufen:

MyFunction(("a", 1), ("b", 2), ("c", 3));

Siehe: Neue Funktionen in C # 7.0

Verwendung eines Wörterbuchs:

myFunction(new Dictionary<string, object>(){
  {"Key", value}, 
  {"Key2", value}});

Was einfach ist, Sie brauchen nur einen new Dictionary<K, V>, nicht für jedes Argument. Es ist trivial, die Schlüssel und Werte zu erhalten.

Oder mit einem anonymen Typ:

myFunction(new {
  Key = value, 
  Key2 = value});

Was innerhalb der Funktion nicht sehr schön ist, müssen Sie nachdenken. Das würde ungefähr so ​​aussehen:

foreach (PropertyInfo property in arg.GetType().GetProperties())
{
  key = property.Name;
  value = property.GetValue(arg, null);
}

(Richtig von meinem Kopf, wahrscheinlich ein paar Fehler ...)

2

Verwenden Sie ein Dictionary ...

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"];
}
2
JP Alioto

Hier ist mehr davon:

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

Einige Details zum Initialisieren eines Wörterbuchs finden Sie here .

2
Chris S

Bei dynamischem Typ in 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);
    }
}

Anrufen mit:

MyFunction(new {Key = "Key1", Value = "Value1"}, new {Key = "Key2", Value = "Value2"});
2
djoyce

Du kannst das machen: 

TestNamedMethod(DateField => DateTime.Now, IdField => 3);

woher DateField und IdField sollen "String" Bezeichner sein. 

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

Die Leistung ist 5% schneller als bei Verwendung von Dictionary. Nachteil: Sie können Variable nicht als Schlüssel verwenden.

1
yeroo

Sie können Tuples verwenden, um etwas Ähnliches wie den Pairing.Of von @Bryan Watts zu erreichen, ohne die zusätzliche Klasse:

public static void MyFunction(params Tuple<string, int>[] pairs)
{
}

MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));
0
Pakman

Sie können auch auf das Nugetpackage "Wertetuple" verweisen, mit dem Sie Folgendes tun können:

public static void MyFunction(params ValueTuple<string, object>[] pairs)
{
    var pair = pairs[1];
    var stringValue = pair.item1;
    var objectValue = pair.item2;
}

Sie können die Methode dann wie folgt aufrufen:

MyFunction(("string",object),("string", object));
0
Rob. E