2009-06-01 30 views
16

tôi dường như viết mã này lặp đi lặp lại và muốn xem liệu có cách nào tốt hơn để thực hiện nó một cách tổng quát hơn không.Cách thanh lịch để chuyển từ danh sách các đối tượng sang từ điển với hai thuộc tính

Tôi bắt đầu với một danh sách các Foo đối tượng

Foo[] foos = GenerateFoos(); 

Tôi nghĩ rằng muốn tạo ra một từ điển nơi quan trọng và giá trị đều thuộc tính của Foo

ví dụ:

Dictionary<string, string> fooDict = new Dictionary<string, string>(): 
foreach (Foo foo in foos) 
{ 
    fooDict[foo.Name] = foo.StreetAddress; 
} 

là có anyway viết mã này chung như nó có vẻ giống như một mẫu cơ bản, nơi có một mảng các đối tượng, một tài sản quan trọng một tài sản giá trị và một từ điển.

Mọi đề xuất?

Tôi đang sử dụng VS 2005 (C#, 2,0)

Trả lời

54

Với LINQ:

var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress); 

(và có, fooDictDictionary<string, string>)


chỉnh sửa để hiển thị sự đau đớn trong VS2005:

Dictionary<string, string> fooDict = 
    Program.ToDictionary<Foo, string, string>(foos, 
     delegate(Foo foo) { return foo.Name; }, 
     delegate(Foo foo) { return foo.StreetAddress; }); 

nơi bạn có (trong 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; 
} 
+0

bất cứ điều gì mà làm việc trong VS2005? – leora

+0

Vâng, bạn có thể viết một cái gì đó tương tự bằng cách sử dụng các phương pháp vô danh và một lớp tiện ích, nhưng nó có thể sẽ làm việc nhiều hơn mã hiện tại của bạn ... –

+0

Ồ, đó là tốt đẹp.Tốt hơn nhiều so với tôi: ( –

6

Nếu bạn đang sử dụng framework 3.5, bạn có thể sử dụng phần mở rộng ToDictionary:

Dictionary<string, string> fooDict = foos.ToDictionary(f => f.Name, f => f.StreetAddress); 

Đối với framework 2.0, mã này là khá nhiều càng đơn giản vì nó có thể.

Bạn có thể cải thiện hiệu suất một chút bằng cách xác định công suất cho từ điển khi bạn tạo ra nó, để nó không phải làm bất cứ tái phân bổ trong khi bạn điền vào nó:

Dictionary<string, string> fooDict = new Dictionary<string, string>(foos.Count): 
+0

bất cứ điều gì mà làm việc trong VS2005? – leora

2

Without LINQ, không có , không có người giúp việc tích hợp cho việc này. Bạn có thể viết một mặc dù:

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

Nó không giống gần như tao nhã như câu trả lời LINQ-based, hiện nó ...

+0

Tôi cần phải kiểm tra, nhưng bạn có thể tìm thấy bạn cần phải xác định các loại chung chung. .. suy luận kiểu chung đã mạnh hơn trong C# 3.0 (nó không phải là tất cả những gì tuyệt vời trong C# 2.0/VS2005) –

+0

Tôi khá chắc chắn loại suy luận chung là trong 2.0, nhưng suy luận đại biểu đã không - nếu có, bạn có thể thả "mới Func " công cụ –

+0

Tất nhiên, tôi luôn luôn dường như quên những gì của công cụ này là trong 2.0 - Tôi chỉ để cho các trình biên dịch của khiếu nại là thiết bị bộ nhớ của tôi :) –

1

Dưới đây là một giải pháp đó là .net 2.0 tương thích sử dụng System.Web .UI.Databinder để thực hiện sự phản chiếu trên tên thuộc tính - bạn mất kiểm tra kiểu thời gian biên dịch.

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

Bạn sẽ gọi như sau:

Dictionary<string, string> fooDict = ToDictionary(foos, "Name", "StreetAddress"); 
Các vấn đề liên quan