Пара ключевых значений в С# Params
Я ищу способ иметь такую функцию, как:
myFunction({"Key", value}, {"Key2", value});
Я уверен, что есть что-то с анонимными типами, что было бы довольно легко, но я этого не вижу.
Единственное решение, которое я могу придумать, - это иметь параметр params KeyValuePair<String, object>[] pairs
, но в конечном итоге это будет примерно так:
myFunction(new KeyValuePair<String, object>("Key", value),
new KeyValuePair<String, object>("Key2", value));
Что, по общему признанию, намного более уродливо.
EDIT:
Чтобы уточнить, я пишу класс Message
для перехода между двумя разными системами. Он содержит ushort
, определяющий тип сообщения, и словарь строки для объекта для "данных", связанных с сообщением. Я хотел бы иметь возможность передавать всю эту информацию в конструкторе, поэтому я могу сделать это:
Agent.SendMessage(new Message(MessageTypes.SomethingHappened, "A", x, "B", y, "C", z));
или похожий синтаксис.
Ответы
Ответ 1
Если синтаксис плохо подходит для другого приличного шаблона, измените синтаксис. Как насчет:
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 } });
Ответ 2
Начиная с С# 7.0, вы можете использовать кортежи значений. С# 7.0 вводит не только новый тип, но и упрощенный синтаксис для типов кортежей, а также для значений кортежей. Тип кортежа просто записывается в виде списка типов, заключенных в фигурные скобки:
(string, int, double)
Соответствующие элементы называются Item1
, Item2
, Item2
. Вы также можете указать дополнительные псевдонимы. Эти псевдонимы являются только синтаксическим сахаром (уловка компилятора С#); кортежи по-прежнему основаны на инвариантной (но общей) 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}");
Это извлекает элементы кортежа в две отдельные переменные key
и value
.
Теперь вы можете легко вызвать MyFunction
с различным количеством аргументов:
MyFunction(("a", 1), ("b", 2), ("c", 3));
Это позволяет нам делать такие вещи, как
DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0));
Смотрите: Новые функции в С# 7.0
Ответ 3
Смешно, я только что создал (минут назад) метод, который позволяет сделать это, используя анонимные типы и отражение:
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;
}
Ответ 4
Немного взлома, но вы можете использовать класс 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
}
}
Ответ 5
Использование словаря:
myFunction(new Dictionary<string, object>(){
{"Key", value},
{"Key2", value}});
Что прямолинейно, вам нужен только один 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);
}
(Staight с моей головы, возможно, некоторые ошибки...)
Ответ 6
Используйте Словарь...
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"];
}
Ответ 7
Здесь больше того же:
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]);
}
}
Некоторые сведения об инициализации словаря можно найти здесь.
Ответ 8
С динамическим типом в С# 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"});
Ответ 9
Вы можете сделать это:
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% быстрее, чем использование словаря. Недостаток: вы не можете использовать переменную в качестве ключа.
Ответ 10
Вы также можете ссылаться на 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));
Ответ 11
Вы можете использовать Tuples для достижения чего-то подобного @Bryan Watts Pairing.Of
без дополнительного класса:
public static void MyFunction(params Tuple<string, int>[] pairs)
{
}
MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));