A pair of key values ​​in C # Params

I am looking for a way to have a function like:

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

I'm sure there is something with anonymous types that would be pretty easy, but I don't see it.

The only solution I can come up with is to have params KeyValuePair<String, object>[] pairs parameter params KeyValuePair<String, object>[] pairs , but in the end it will be something like this:

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

Which is admittedly much more ugly.

EDIT:

To clarify, I am writing a Message class to transition between two different systems. It contains a ushort that defines the type of message, and a string dictionary for the object for the "data" associated with the message. I would like to be able to pass all this information to the constructor, so I can do this:

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

or similar syntax.

+31
source share
11 answers

If the syntax is not good for another decent template, change the syntax. What about:

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

Using:

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

Even more interesting would be to add an extension method to string to make it available:

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

Using:

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

Change You can also use dictionary syntax without common brackets, based on Dictionary<,> :

 public void MyFunction(MessageArgs args) { // ... } public class MessageArgs : Dictionary<string, object> {} 

Using:

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

Starting with C # 7.0, you can use tuples of values. C # 7.0 introduces not only a new type, but also a simplified syntax for tuple types, as well as for tuple values. The tuple type is simply written as a list of types enclosed in braces:

 (string, int, double) 

The corresponding items are called Item1 , Item2 , Item2 . You can also specify additional aliases. These aliases are syntactic sugar only (C # compiler trick); tuples are still based on the invariant (but common) System.ValueTuple<T1, T2, ...> struct .

 (string name, int count, double magnitude) 

Tuple values ​​have similar syntax except that you specify expressions instead of types

 ("test", 7, x + 5.91) 

or with aliases

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

Example with params array:

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

It is also possible to deconstruct a tuple like this

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

This extracts the tuple elements into two separate variables, key and value .

Now you can easily call MyFunction with a different number of arguments:

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

This allows us to do things like

 DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0)); 

See: New Features in C # 7.0

+14
source

Funny, I just created (minutes ago) a method that allows you to do this using anonymous types and reflection:

 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
source

A bit of a hack, but you can use the Message class for the IEnumerable interface and give it the Add method. Then you can use the collection initializer 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 } } 
+7
source

Using a dictionary:

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

Which is straightforward, you only need one new Dictionary<K, V> , and not for each argument. It is trivial to get keys and values.

Or with an anonymous type:

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

What is not very nice to use inside the function, you will need reflection. It will look something like this:

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

(Staight with my head, maybe some mistakes ...)

+2
source

Use the 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
source

Here is more of the same:

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

Some information on initializing a dictionary can be found here .

+2
source

With dynamic type 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); } } 

Call using:

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

You can do it:

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

where DateField and IdField must be "string" identifiers.

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

Performance is 5% faster than using a dictionary. Disadvantage: you cannot use a variable as a key.

+1
source

You can also reference nugetpackage "valuetuple", which allows you to do the following:

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

Then you can call the method as follows:

 MyFunction(("string",object),("string", object)); 
+1
source

You can use Tuples to achieve something like @Bryan Watts Pairing.Of without an extra class:

 public static void MyFunction(params Tuple<string, int>[] pairs) { } MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2)); 
0
source

Source: https://habr.com/ru/post/972732/


All Articles