私はこのコードを何度も書いているようで、より一般的にそれを行うより良い方法があるかどうかを確認したいと思いました。
Fooオブジェクトのリストから始めます
Foo[] foos = GenerateFoos();
キーと値の両方がFooのプロパティである辞書を作成したいと思います
例えば:
Dictionary<string, string> fooDict = new Dictionary<string, string>():
foreach (Foo foo in foos)
{
fooDict[foo.Name] = foo.StreetAddress;
}
オブジェクトの配列、キープロパティ、値プロパティ、ディクショナリがある基本的なテンプレートのように見えるので、このコードを一般的に書く方法はありますか?.
助言がありますか?
VS 2005(C#、2.0)を使用しています
LINQの場合:
var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress);
(そして、はい、fooDict
はDictionary<string, string>
)
編集してVS2005の痛みを示します。
Dictionary<string, string> fooDict =
Program.ToDictionary<Foo, string, string>(foos,
delegate(Foo foo) { return foo.Name; },
delegate(Foo foo) { return foo.StreetAddress; });
あなたが持っている場所(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;
}
フレームワーク3.5を使用している場合は、ToDictionary
拡張機能を使用できます。
Dictionary<string, string> fooDict = foos.ToDictionary(f => f.Name, f => f.StreetAddress);
フレームワーク2.0の場合、コードはできる限り単純です。
作成時にディクショナリの容量を指定することにより、パフォーマンスを少し向上させることができます。これにより、ディクショナリの入力中に再割り当てを行う必要がなくなります。
Dictionary<string, string> fooDict = new Dictionary<string, string>(foos.Count):
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; }));
LINQベースの回答ほど洗練されていないように見えますが...
System.Web.UI.Databinderを使用してプロパティ名を反映する.net 2.0互換のソリューションを次に示します-コンパイル時の型チェックが失われます。
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);
}
次のように呼び出します。
Dictionary<string, string> fooDict = ToDictionary(foos, "Name", "StreetAddress");