web-dev-qa-db-ja.com

C#パラメータのキーと値のペア

私は次のような機能を持つ方法を探しています:

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

かなり簡単な匿名型の何かがあると確信していますが、私はそれを見ていません。

私が考えることができる唯一の解決策は、params KeyValuePair<String, object>[] pairsパラメータですが、最終的には次のようなものになります。

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

確かに、これはもっと醜いです。

編集:

明確にするために、2つの異なるシステム間で受け渡すMessageクラスを作成しています。これには、メッセージタイプを指定するushortと、メッセージに関連付けられた「データ」を対象とする文字列のディクショナリが含まれます。コンストラクターでこのすべての情報を渡すことができるようにしたいので、これを行うことができます:

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

または同様の構文。

34
Quantumplation

構文がまともなパターンに適さない場合は、構文を変更します。どうですか:

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

使用法:

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

さらに興味深いのは、拡張メソッドをstringに追加してペアリングできるようにすることです。

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

使用法:

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

編集Dictionary<,>から派生させることで、総称括弧なしで辞書構文を使用することもできます。

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

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

使用法:

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

C#7.0以降、値のタプルを使用できます。 C#7.0では、新しい型が導入されただけでなく、Tuple型とTuple値の構文も簡素化されました。タプル型は、中括弧で囲まれた型のリストとして単純に記述されます。

_(string, int, double)
_

対応する要素の名前は_Item1_、_Item2_、_Item2_です。オプションのエイリアスを指定することもできます。これらのエイリアスは、単なる構文上の砂糖(C#コンパイラのトリック)です。タプルは依然として不変式(ただし総称) _System.ValueTuple<T1, T2, ...>_ struct に基づいています。

_(string name, int count, double magnitude)
_

タプル値は、タイプの代わりに式を指定することを除いて、同様の構文を持っています

_("test", 7, x + 5.91)
_

またはエイリアス付き

_(name: "test", count: 7, magnitude: x + 5.91)
_

params配列の例:

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

このようにタプルを分解することも可能です

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

これにより、タプルの項目が2つの別々の変数keyおよびvalueに抽出されます。

これで、さまざまな数の引数を使用してMyFunctionを簡単に呼び出すことができます。

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

それは私たちが次のようなことをすることを可能にします

_DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0));
_

参照: C#7.0の新機能

おかしい、私は(分前に)匿名型とリフレクションを使用してそれを可能にするメソッドを作成しました:

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

少しハックしましたが、MessageクラスにIEnumerableインターフェースを実装させ、Addメソッドを与えることもできます。その後、コレクション初期化構文を使用できます。

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

辞書を使用する:

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

簡単です。必要なのは1つだけですnew Dictionary<K, V>、各引数ではありません。キーと値を取得するのは簡単です。

または匿名型:

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

関数内で使用するのはあまり良くありません。リフレクションが必要になります。これは次のようになります。

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

(私の頭からまっすぐ、おそらくいくつかのエラー...)

3

辞書 ...を使用します.

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

これは同じです:

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

辞書の初期化に関する詳細は、 here にあります。

2
Chris S

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

次を使用して呼び出す:

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

出来るよ:

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

どこ DateField そして IdField 「文字列」識別子であることになっています。

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

辞書を使用するよりもパフォーマンスが5%高速です。欠点:変数をキーとして使用できません。

1
yeroo

Nugetpackage "valuetuple"を参照することもできます。これにより、次のことが可能になります。

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

その後、次のようにメソッドを呼び出すことができます。

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

タプルを使用して、@ Bryan WattsのPairing.Of追加のクラスなし:

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

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

だから私は新しいので現在コメントを追加することはできませんが、これはPairing.ofクラスを@Bryan Wattsの一般的なものにして、他のクラスで簡単に使用できるようにするという@Bryan Wattsのアイデアを改善するための提案にすぎません。

public class Pairing 
{
    public static KeyValuePair<TKey, TValue> of<TKey, TValue>(TKey key, TValue value)
    {
        return new KeyValuePair<TKey, TValue>(key, value);
    }
}
0
pumbas600