Frage

Ich bin auf der Suche nach einem Weg, um eine Funktion zu haben, wie:

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

Ich bin sicher, es ist etwas mit anonymen Typen, die ziemlich einfach sein würde, aber ich sehe es nicht.

Die einzige Lösung, die ich denken kann, ist einen params KeyValuePair<String, object>[] pairs Parameter zu haben, aber das endet etwas ähnlich zu sein:

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

Welche ist zugegebenermaßen viel hässlicher.

EDIT:

Um zu klären, ich bin eine Message Klasse Schreiben zwischen zwei verschiedenen Systemen zu übergeben. Es enthält ein ushort den Nachrichtentyp, und ein Wörterbuch der String-Objekt für „Data“ im Zusammenhang mit der Meldung angeben. Ich möchte in der Lage sein, all diese Informationen im Konstruktor übergeben, so dass ich bin in der Lage, dies zu tun:

Agent.SendMessage(new Message(MessageTypes.SomethingHappened, "A", x, "B", y, "C", z));

oder ähnliche Syntax.

War es hilfreich?

Lösung

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

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

Verbrauch:

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

Noch interessanter wäre eine Erweiterungsmethode zu string hinzufügen, um es paarbar:

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

Verbrauch:

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

Bearbeiten : Sie können auch das Wörterbuch Syntax ohne die generischen Klammern verwenden, indem Sie von Dictionary<,> ableiten:

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

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

Verbrauch:

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

Andere Tipps

Da C # 7.0 können Sie Wertetupeln verwenden. C # 7.0 führt nicht nur einen neuen Typ, sondern eine vereinfachte Syntax für Tupels Typen sowie für Tupel Werte. Ein Tupel-Typ wird einfach als eine Liste von Typen von Klammern umgeben geschrieben:

(string, int, double)

Die entsprechenden Elemente werden genannt Item1, Item2, Item2. Sie können auch optionale Aliasnamen angeben. Diese Aliase sind nur syntaktischer Zucker (ein Trick der C # Compiler); die Tupel auf der Invarianten nach wie vor basiert (aber allgemein) neue Features in C # 7.0

Lustig, Ich habe gerade (Minuten) ein Verfahren, das die unter Verwendung von anonymen Typen und Reflexion zu tun erlaubt:

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

Bit A ein Hack, aber man konnte Ihre Message Klasse hat den IEnumerable-Schnittstelle implementieren und gibt ihm eine Add Methode. Sie werden dann in der Lage sein Auflistungsinitialisierer Syntax:

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

Verwenden Sie ein Wörterbuch ...

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

Hier ist mehr von der gleichen:

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 über ein Wörterbuch Initialisierung können hier .

Mit einem Wörterbuch:

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

Welche geradlinig ist, müssen Sie nur eine 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 nicht sehr schön ist innerhalb der Funktion zu verwenden, müssen Sie Reflexion benötigen. Dies würde in etwa so aussehen:

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

(Staight von meinem Kopf, wahrscheinlich einige Fehler ...)

Bei der dynamischen 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);
    }
}

Anruf mit:

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

Sie können das tun:

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

Dabei steht Datefield und IdField sollen ein 'String' Bezeichner sein.

Die 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 Wörterbuch verwenden. Nachteil:. Sie können nicht Variable als Schlüssel verwenden,

Sie können auch die nugetpackage „valuetuple“ verweisen, die 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 dann rufen Sie die Methode wie folgt aus:

MyFunction(("string",object),("string", object));

Sie könnten Tupeln verwenden etwas Ähnliches wie @Bryan Watts Pairing.Of ohne Extraklasse zu erreichen:

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

MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top