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对象列表开始
Foo[] foos = GenerateFoos();
I think want to create a dictionary where the key and value are both properties of Foo
我想创建一个字典,其中键和值都是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)
我正在使用VS 2005(C#,2.0)
4 个解决方案
#1
56
With LINQ:
使用LINQ:
var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress);
(and yes, fooDict
is Dictionary<string, string>
)
(是的,fooDict是Dictionary
edit to show the pain in VS2005:
编辑以显示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;
}
#2
6
If you are using framework 3.5, you can use the ToDictionary
extension:
如果您使用的是框架3.5,则可以使用ToDictionary扩展:
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.
对于框架2.0,代码非常简单。
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):
#3
2
Without LINQ, no, there's no built-in helpers for this. You could write one though:
没有LINQ,不,没有内置帮助器。你可以写一个:
// 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...
它看起来不像基于LINQ的答案那么优雅,是吗......
#4
1
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.
这是一个与.net 2.0兼容的解决方案,它使用System.Web.UI.Databinder对属性名称进行反射 - 您将失去编译时类型检查。
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");
#1
56
With LINQ:
使用LINQ:
var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress);
(and yes, fooDict
is Dictionary<string, string>
)
(是的,fooDict是Dictionary
edit to show the pain in VS2005:
编辑以显示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;
}
#2
6
If you are using framework 3.5, you can use the ToDictionary
extension:
如果您使用的是框架3.5,则可以使用ToDictionary扩展:
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.
对于框架2.0,代码非常简单。
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):
#3
2
Without LINQ, no, there's no built-in helpers for this. You could write one though:
没有LINQ,不,没有内置帮助器。你可以写一个:
// 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...
它看起来不像基于LINQ的答案那么优雅,是吗......
#4
1
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.
这是一个与.net 2.0兼容的解决方案,它使用System.Web.UI.Databinder对属性名称进行反射 - 您将失去编译时类型检查。
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");