I'm looking for a way to have a function such as:
myFunction({"Key", value}, {"Key2", value});
I'm sure there's something with anonymous types that would be pretty easy, but I'm not seeing it.
The only solution I can think of is to have a params KeyValuePair<String, object>[] pairs parameter, but that ends up being something similar to:
myFunction(new KeyValuePair<String, object>("Key", value),
new KeyValuePair<String, object>("Key2", value));
Which is, admittedly, much uglier.
EDIT:
To clarify, I'm writing a Message class to pass between 2 different systems. It contains a ushort specifying the the Message Type, and a dictionary of string to object for "Data" associated with the message. I'd like to be able to pass all this information in the constructor, so I am able to do this:
Agent.SendMessage(new Message(MessageTypes.SomethingHappened, "A", x, "B", y, "C", z));
or similar syntax.
When the syntax is bad for an otherwise decent pattern, change the syntax. How 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);
}
}
Usage:
MyFunction(Pairing.Of("Key1", 5), Pairing.Of("Key2", someObject));
Even more interesting would be to add an extension method to string to make it pairable:
public static KeyValuePair<string, object> PairedWith(this string key, object value)
{
return new KeyValuePair<string, object>(key, value);
}
Usage:
MyFunction("Key1".PairedWith(5), "Key2".PairedWith(someObject));
Edit: You can also use the dictionary syntax without the generic brackets by deriving from Dictionary<,>:
public void MyFunction(MessageArgs args)
{
// ...
}
public class MessageArgs : Dictionary<string, object>
{}
Usage:
MyFunction(new MessageArgs { { "Key1", 5 }, { "Key2", someObject } });
Since C# 7.0, you can use value tuples. C# 7.0 not only introduces a new type but a simplified syntax for tuple types and for tuple values. A tuple type is simply written as a list of types surrounded by braces:
(string, int, double)
The corresponding elements are named Item1, Item2, Item2. You can also specify optional aliases. These aliases are only syntactic sugar (a trick of the C# compiler); the tuples are still based on the invariant (but generic) System.ValueTuple<T1, T2, ...> struct.
(string name, int count, double magnitude)
Tuple values have a similar syntax, except that you specify expressions instead of types
("test", 7, x + 5.91)
or with the 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 items of the tuple in two separate variables key and value.
Now, you can call MyFunction with a varying number of arguments easily:
MyFunction(("a", 1), ("b", 2), ("c", 3));
It allows us to do things like
DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0));
See: New Features in C# 7.0
Funny, I just created (minutes ago) a method that allows to do that, 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;
}
A bit of a hack, but you could have your Message class implement the IEnumerable interface and give it an Add method. You'll then be able to use 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
}
}
Using a dictionary:
myFunction(new Dictionary<string, object>(){
{"Key", value},
{"Key2", value}});
Which is straight forward, you need only one new Dictionary<K, V>, not for each argument. It's trivial to get the keys and values.
Or with an anonymous type:
myFunction(new {
Key = value,
Key2 = value});
Which is not very nice to use inside the function, you'll need reflection. This would look something like this:
foreach (PropertyInfo property in arg.GetType().GetProperties())
{
key = property.Name;
value = property.GetValue(arg, null);
}
(Staight from my head, probably some errors...)
Use a 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"];
}
Here's 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 details on initialising a dictionary can be found here.
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"});
You can do that:
TestNamedMethod(DateField => DateTime.Now, IdField => 3);
where DateField and IdField are supposed to be a 'string' identifiers.
The 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 Dictionary. Disadvantage: you can't use variable as a key.
You could also reference the 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;
}
You can then call the method like this:
MyFunction(("string",object),("string", object));
You could use Tuples to achieve something similar to #Bryan Watts's Pairing.Of without the extra class:
public static void MyFunction(params Tuple<string, int>[] pairs)
{
}
MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));
So I'm new and can't currently add comments, but this is just a suggestion to improve #Bryan Watts's idea of the Pairing.of class by making it generic, allowing it to be easily used by other classes.
public class Pairing
{
public static KeyValuePair<TKey, TValue> of<TKey, TValue>(TKey key, TValue value)
{
return new KeyValuePair<TKey, TValue>(key, value);
}
}
Related
Trying to copy values from an existing NameValueCollection object to a Dictionary. I have the following code below to do that but seems the Add does not accept that my keys and values are as Strings
IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
public void copyFromNameValueCollection (NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
Note: NameValueCollection contains String keys and values and so I simply want to provide here a method to allow copying of those to a generic dictionary.
Extension method plus linq:
public static Dictionary<string, string> ToDictionary(this NameValueCollection nvc) {
return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]);
}
//example
var dictionary = nvc.ToDictionary();
It doesn't make sense to use generics here since you can't assign strings to some arbitrary generic type:
IDictionary<string, string> dict = new Dictionary<string, string>();
public void copyFrom(NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
although you should probably create a method to create a new dictionary instead:
public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
{
IDictionary<string, string> dict = new Dictionary<string, string>();
foreach (var k in col.AllKeys)
{
dict.Add(k, col[k]);
}
return dict;
}
which you can use like:
NameValueCollection nvc = //
var dictionary = nvc.ToDictionary();
If you want a general way of converting the strings in the collection into the required key/value types, you can use type converters:
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this NameValueCollection col)
{
var dict = new Dictionary<TKey, TValue>();
var keyConverter = TypeDescriptor.GetConverter(typeof(TKey));
var valueConverter = TypeDescriptor.GetConverter(typeof(TValue));
foreach(string name in col)
{
TKey key = (TKey)keyConverter.ConvertFromString(name);
TValue value = (TValue)valueConverter.ConvertFromString(col[name]);
dict.Add(key, value);
}
return dict;
}
parameters.AllKeys.ToDictionary(t => t, t => parameters[t]);
Use LINQ:
public static IDictionary<string, string> ToDictionary(this NameValueCollection collection)
{
return collection.Cast<string>().ToDictionary(k => k, v => collection[v]);
}
Usage:
IDictionary<string, string> dic = nv.ToDictionary();
Super-Short Version
var dataNvc = HttpUtility.ParseQueryString(data);
var dataCollection = dataNvc.AllKeys.ToDictionary(o => o, o => dataNvc[o]);
If you know that your dictionary is always going to contain strings, specify it to contain strings instead of making your class generic:
IDictionary<string, string> dict = new Dictionary<string, string>();
With this, things will "just work" as written (without the generic method specification).
If you need this to be a generic class, and hold generic data, you need some way to convert from string to TKey and string to TValue. You could provide delegates to your copy method to do this:
public void CopyFrom(NameValueCollection a, Func<string, TKey> keyConvert, Func<string, TValue> valueConvert)
{
foreach(var k in a.AllKeys)
{
dict.Add(keyConvert(k), valueConvert(a[k]));
}
}
You would then need to pass a delegate in that would perform the conversion from string to TValue and string to TKey.
You should not forget about EqualityComparer. But it is not a public property. So, you should use reflection to get it.
public static IEqualityComparer GetEqualityComparer(this NameObjectCollectionBase nameObjectCollection)
{
PropertyInfo propertyInfo = typeof(NameObjectCollectionBase).GetProperty("Comparer", BindingFlags.Instance | BindingFlags.NonPublic);
return (IEqualityComparer)propertyInfo.GetValue(nameObjectCollection);
}
public static IEqualityComparer<string> GetEqualityComparer(this NameValueCollection nameValueCollection)
{
return (IEqualityComparer<string>)((NameObjectCollectionBase)nameValueCollection).GetEqualityComparer();
}
public static Dictionary<string, string> ToDictionary(this NameValueCollection nameValueCollection)
{
Dictionary<string, string> dictionary =
nameValueCollection.AllKeys.ToDictionary(x => x, x => nameValueCollection[x], nameValueCollection.GetEqualityComparer());
return dictionary;
}
I can't figure out the syntax to do inline collection initialization for:
var a = new List<KeyValuePair<string, string>>();
Note that the dictionary collection initialization { { key1, value1 }, { key2, value2 } } depends on the Dictionary's Add(TKey, TValue) method. You can't use this syntax with the list because it lacks that method, but you could make a subclass with the method:
public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
public class Program
{
public static void Main()
{
var list = new KeyValueList<string, string>
{
{ "key1", "value1" },
{ "key2", "value2" },
{ "key3", "value3" },
};
}
}
Pretty straightforward:
var a = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("A","B"),
new KeyValuePair<string, string>("A","B"),
new KeyValuePair<string, string>("A","B"),
};
Note that you can leave the trailing comma after the last element (probably because .net creators wanted to make automatic code-generation easier), or remove the () brackets of the list contructor and the code still compiles.
Another alternative that doesn't require making a subclass:
List<KeyValuePair<String, String>> list = new Dictionary<String, String>
{
{"key1", "value1"},
{"key2", "value2"},
}.ToList();
As mentioned in the comments: drawbacks with this method include possible loss of ordering and inability to add duplicate keys.
Since collection initializers (C# 6.0) have not been mentioned here:
Implementation
public static class InitializerExtensions
{
public static void Add<T1, T2>(this ICollection<KeyValuePair<T1, T2>> target, T1 item1, T2 item2)
{
if (target == null)
throw new ArgumentNullException(nameof(target));
target.Add(new KeyValuePair<T1, T2>(item1, item2));
}
}
Usage
var list = new List<KeyValuePair<string, string>> { {"ele1item1", "ele1item2"}, { "ele2item1", "ele2item2" } };
How to make it work
Just include the right using statements in your file so that InitializerExtensions is available (meaning you could call InitializerExtensions.Add explicitly) and the special collection initializer syntax will become available if you are using VS 2015 or higher.
Any initialization is done by object(params_if_exist) { any public member or instance};
f.e. var list = new List<int> {1,2,3};
var bw = new BackgroundWorker() {WorkerSupportsCancellation = true};
I need to create a dictionary that has 2 values per key, and it must return one of the 2 values with the same probability.
Example:
myDicry
{
key = "A", value1=15, value2=56;
}
int firstCall = myDicry["A"]; // = 15
int secondCall = myDicry["A"]; // = 56
It would be possible to write an IDictionary<TKey, TValue> implementation that behaved in this manner, but that would not be a good idea: most people would find a non-deterministic indexer for a collection-class very unintuitive.
Instead, I suggest you make this the responsibility of the value for a key, rather than the Dictionary itself. One option would be to write a custom-type that is capable of picking from a set of possibilities with equal probability. For example:
public class UnbiasedRandomPicker<T>
{
private readonly Random _rand = new Random();
private readonly T[] _possibilities;
public UnbiasedRandomPicker(params T[] possibilities)
{
// argument validation omitted
_possibilities = possibilities;
}
public T GetRandomValue()
{
return _possibilities[_rand.Next(_possibilities.Length)];
}
}
You could then use the dictionary like this:
var dict = new Dictionary<string, UnbiasedRandomPicker<int>>
{
{"A", new UnbiasedRandomPicker<int>(15, 56)},
{"B", new UnbiasedRandomPicker<int>(25, 13)}
};
int randomValueFromA = dict["A"].GetRandomValue();
There's nothing built into the framework to do this, but you'd probably want to implement it by creating a "wrapper" type which had a Dictionary<TKey, Tuple<TValue, TValue>>. You'd then write an indexer to choose appropriately between the two values.
I would actually just implement this in a class that uses a Dictionary<TKey, TValue[]> internally. That way you could even implement the type to have a variable number of values per key.
Like:
class RandomDictionary<TKey, TValue>
{
Dictionary<TKey, TValue[]> m_dict;
Random m_random;
public RandomDictionary()
{
m_dict = new Dictionary<TKey, TValue[]>();
m_random = new Random();
}
public TValue this[TKey key]
{
get
{
TValue[] values = m_dict[key];
return values[m_random.Next(0, values.Length)];
}
}
public void Define(TKey key, params TValue[] values)
{
m_dict[key] = new TValue[values.Length];
Array.Copy(values, m_dict[key], values.Length);
}
public bool TryGetValue(TKey key, out TValue value)
{
TValue[] values;
if (!m_dict.TryGetValue(key, out values))
{
value = default(TValue);
return false;
}
value = values[m_random.Next(0, values.Length)];
return true;
}
}
Use Tuple as dictionary value type.
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
// ...
int secondValue = doubleDictionary["A"].Item2;
You could also write an extension method for the dictionary, so you could create something like this:
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
doubleDictionary.GetRandomValueForKey("A");
Then you can use this with any dictionary.
public static void GetRandomValueForKey(this Dictionary<string, Tuple<int, int>> dict,
string key)
{
... Code to return the value
}
^^ that was written off the top of my head, so please excuse me if this is slightly wrong.
This below code will solve the dictionary part of the problem and make the randomization customizable so that you can apply a level so pseudo-randomness that suits your needs. (or simply hard code it instead of the use of a functor)
public class DoubleDictionary<K, T> : IEnumerable<KeyValuePair<K, T>>
{
private readonly Dictionary<K, Tuple<T, T>> _dictionary = new Dictionary<K, Tuple<T, T>>();
private readonly Func<bool> _getFirst;
public DoubleDictionary(Func<bool> GetFirst) {
_getFirst = GetFirst;
}
public void Add(K Key, Tuple<T, T> Value) {
_dictionary.Add(Key, Value);
}
public T this[K index] {
get {
Tuple<T, T> pair = _dictionary[index];
return GetValue(pair);
}
}
private T GetValue(Tuple<T, T> Pair) {
return _getFirst() ? Pair.Item1 : Pair.Item2;
}
public IEnumerable<K> Keys {
get {
return _dictionary.Keys;
}
}
public IEnumerable<T> Values {
get {
foreach (var pair in _dictionary.Values) {
yield return GetValue(pair);
}
}
}
IEnumerator<KeyValuePair<K, T>> IEnumerable<KeyValuePair<K, T>>.GetEnumerator() {
foreach (var pair in _dictionary) {
yield return new KeyValuePair<K, T>(pair.Key, GetValue(pair.Value));
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable<KeyValuePair<K, T>>)this).GetEnumerator();
}
}
If 'value' is an incoming generic dictionary whose types are unknown/don't matter, how do I take its entries and put them into a target dictionary of type IDictionary<object, object> ?
if(type == typeof(IDictionary<,>))
{
// this doesn't compile
// value is passed into the method as object and must be cast
IDictionary<,> sourceDictionary = (IDictionary<,>)value;
IDictionary<object,object> targetDictionary = new Dictionary<object,object>();
// this doesn't compile
foreach (KeyValuePair<,> sourcePair in sourceDictionary)
{
targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
}
return targetDictionary;
}
EDIT:
Thanks for the responses so far.
The problem here is that the argument to Copy is only known as type 'object'. For example:
public void CopyCaller(object obj)
{
if(obj.GetType() == typeof(IDictionary<,>)
Copy(dictObj); // this doesn't compile
}
Make your method generic as well and then you'll be able to do what you're doing. You won't have to change your usage pattern since the compiler will be able to infer generic types from input types.
public IDictionary<object, object> Copy(IDictionary<TKey, TValue> source)
{
IDictionary<object,object> targetDictionary = new Dictionary<object,object>();
foreach (KeyValuePair<TKey, TValue> sourcePair in sourceDictionary)
{
targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
}
return targetDictionary;
}
If you don't really need to convert it from IDictionary<TKey, TValue> to IDictionary<object, object> then you can use the copy constuctor of Dictionary<TKey, TValue> which accepts another dictionary as input and copies all values--just like you're doing now.
You can exploit the fact that generic dictionaries implement the IDictionary interface.
public static Dictionary<object, object> CreateCopy(IDictionary source)
{
var copy = new Dictionary<object, object>(source.Count);
foreach (DictionaryEntry entry in source)
{
copy.Add(entry.Key, entry.Value);
}
return copy;
}
Usage example:
var source = new Dictionary<int, string>() { { 1, "Foo" }, { 2, "Bar" }, };
var copy = CreateCopy(source);
Console.WriteLine(String.Join(", ", copy.Values));
Output:
Foo, Bar
Here is a method (don't leave it as static, unless you need it to be, I wrote it in a quick console app) that basically converts a Dictionary of any type to an object/object dictionary.
private static Dictionary<object,object> DeTypeDictionary<T,U>(Dictionary<T,U> inputDictionary)
{
Dictionary<object, object> returnDictionary = new Dictionary<object, object>();
foreach(T key in inputDictionary.Keys)
{
if( (key is object) && (inputDictionary[key] is object))
{
returnDictionary.Add(key, inputDictionary[key]);
}
else
{
//sorry these aren't objects. they may be dynamics.
continue;
}
}
return returnDictionary;
}
...and here is how you use it...
Dictionary<string, DateTime> d = new Dictionary<string, DateTime>();
d.Add("rsgfdg", DateTime.Now);
d.Add("gfdsgd", DateTime.Now);
Dictionary<object, object> newDictionary = DeTypeDictionary<string, DateTime>(d);
So you have an object that may be a Dictionary and you want to:
Test it's a dictionary
Act on it appropriately if it is
Let's start with a generic function that does what you want if you knew the type arguments:
class Bar
{
public static void Foo<TKey, TValue>(Dictionary<TKey, TValue> input) { ... }
}
Now we'll just have to do some reflection
bool TryHandleDictionary(object o)
{
var t = o.GetType();
if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Dictionary<,>)) return false;
var m = typeof(Bar).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static);
var m1 = m.MakeGenericMethod(t.GetGenericArguments());
m1.Invoke(null, new[] { o });
return true;
}
This may be a fix for you but you'll need .net 3.5 or greater to use the var keyword.
// this should compile
foreach (var sourcePair in sourceDictionary)
{
targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
}
i seem to write this code over and over again and wanted to see if there was a better way of doing it more generically.
I start out with a list of Foo objects
Foo[] foos = GenerateFoos();
I think want to create a dictionary where the key and value are both properties of Foo
for example:
Dictionary<string, string> fooDict = new Dictionary<string, string>():
foreach (Foo foo in foos)
{
fooDict[foo.Name] = foo.StreetAddress;
}
is there anyway of writing this code generically as it seems like a basic template where there is an array of objects, a key property a value property and a dictionary.
Any suggestions?
I am using VS 2005 (C#, 2.0)
With LINQ:
var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress);
(and yes, fooDict is Dictionary<string, string>)
edit to show the pain in VS2005:
Dictionary<string, string> fooDict =
Program.ToDictionary<Foo, string, string>(foos,
delegate(Foo foo) { return foo.Name; },
delegate(Foo foo) { return foo.StreetAddress; });
where you have (in Program):
public static Dictionary<TKey, TValue> ToDictionary<TSource, TKey, TValue>(
IEnumerable<TSource> items,
Converter<TSource, TKey> keySelector,
Converter<TSource, TValue> valueSelector)
{
Dictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();
foreach (TSource item in items)
{
result.Add(keySelector(item), valueSelector(item));
}
return result;
}
If you are using framework 3.5, you can use the ToDictionary extension:
Dictionary<string, string> fooDict = foos.ToDictionary(f => f.Name, f => f.StreetAddress);
For framework 2.0, the code is pretty much as simple as it can be.
You can improve the performance a bit by specifying the capacity for the dictionary when you create it, so that it doesn't have to do any reallocations while you fill it:
Dictionary<string, string> fooDict = new Dictionary<string, string>(foos.Count):
Without LINQ, no, there's no built-in helpers for this. You could write one though:
// I forget if you need this delegate definition -- this may be already defined in .NET 2.0
public delegate R Func<T,R>(T obj);
public static Dictionary<K,V> BuildDictionary<T,K,V>(IEnumerable<T> objs, Func<T,K> kf, Func<T,V> vf)
{
Dictionary<K,V> d = new Dictionary<K,V>();
foreach (T obj in objs)
{
d[kf(obj)] = vf(obj);
}
return d;
}
Dictionary<string, string> fooDict = BuildDictionary(foos, new Func<Foo,string>(delegate(Foo foo) { return foo.Name; }), new Func<Foo,string>(delegate(Foo foo) { return foo.StreetAddress; }));
It doesn't look nearly as elegant as the LINQ-based answers, does it...
Here's a solution that's .net 2.0 compatible that uses System.Web.UI.Databinder to do the reflection on the property name - you lose compile-time type checking.
public static Dictionary<string, string> ToDictionary<T>(List<T> list, string keyName, string valueName)
{
Dictionary<string, string> outputDictionary = new Dictionary<string, string>();
foreach (T item in list)
{
string key = Eval<T, string>(item, keyName);
string value = Eval<T, string>(item, valueName);
output[key] = value;
}
return outputDictionary;
}
public static TOut Eval<TIn, TOut>(TIn source, string propertyName)
{
object o = DataBinder.GetPropertyValue(source, propertyName);
if (o is TOut)
return (TOut)o;
return default(TOut);
}
You would call as follows:
Dictionary<string, string> fooDict = ToDictionary(foos, "Name", "StreetAddress");