2012-03-23 25 views
2

我似乎無法找到一種方法讓LINQ從指定的存取器中返回值。 我知道每個對象的訪問器的名稱,但我不確定是否有可能將請求的訪問器作爲變量傳遞或以其他方式實現所需的重構。LINQ到對象:有沒有一種方法可以傳遞給LINQ從中獲取值的訪問器?

考慮下面的代碼片段:

// "value" is some object with accessors like: format, channels, language 
row = new List<String> { 
String.Join(innerSeparator, (from item in myObject.Audio 
    orderby item.Key ascending 
    select item.Value.format).ToArray()), 
String.Join(innerSeparator, (from item in myObject.Audio 
    orderby item.Key ascending 
    select item.Value.channels).ToArray()), 
String.Join(innerSeparator, (from item in myObject.Audio 
    orderby item.Key ascending 
    select item.Value.language).ToArray()), 
// ... 
} 

我想重構這個到使用指定的訪問,或者是通過一個委託的方法,但我看不出怎麼會工作。

string niceRefactor(myObj myObject, string /* or whatever type */ ____ACCESSOR) { 
    return String.Join(innerSeparator, (from item in myObject.Audio 
      orderby item.Key ascending 
      select item.Value.____ACCESSOR).ToArray()); 
} 

我已經寫了相當數量的C#,但對於LINQ的神奇,我還是一個新手。這是正確的方法嗎?你會如何重構這個?

回答

3

你可以通過Func<AudioType, object>來選擇你想要的財產:

string niceRefactor(myObj myObject, Func<AudioType,object> propertySelector) 
{ 
    return String.Join(innerSeparator, (from item in myObject.Audio 
             orderby item.Key ascending 
             select propertySelector(item.value)).ToArray()); 
} 

這假定AudioType是音頻鍵值對返回的值項目的類型。

然後你可以調用你的方法,例如像這樣:

string result = niceRefactor(myObject, x => x.format); 
+0

他怎麼會調用這個函數,請提供樣品 – 2012-03-23 17:33:26

+0

感謝 - 正如我所想? :)........ – 2012-03-23 17:37:22

4

我提取最明顯的共性入手:

var audioItems = myObject.Audio.OrderBy(item => item.Key); 
row = new List<String> { 
    String.Join(innerSeparator, audioItems.Select(x => x.Value).ToArray()); 
    String.Join(innerSeparator, audioItems.Select(x => x.Format).ToArray()); 
    String.Join(innerSeparator, audioItems.Select(x => x.Channels).ToArray()); 
    String.Join(innerSeparator, audioItems.Select(x => x.Language).ToArray()); 
} 

如果我使用.NET 4,我然後取出ToArray電話爲string.Join有更多的重載現在:

var audioItems = myObject.Audio.OrderBy(item => item.Key); 
row = new List<String> { 
    String.Join(innerSeparator, audioItems.Select(x => x.Value)); 
    String.Join(innerSeparator, audioItems.Select(x => x.Format)); 
    String.Join(innerSeparator, audioItems.Select(x => x.Channels)); 
    String.Join(innerSeparator, audioItems.Select(x => x.Language)); 
} 

可能停在那裏。但是,如果你願意,你可以隨時添加其他擴展方法:

public static string Separate<T>(this IEnumerable<T> items, string separator) 
{ 
    return string.Join(separator, items); 
} 

然後:

var audioItems = myObject.Audio.OrderBy(item => item.Key); 
row = new List<String> { 
    audioItems.Select(x => x.Value).Separate(innerSeparator)); 
    audioItems.Select(x => x.Format).Separate(innerSeparator)); 
    audioItems.Select(x => x.Channels).Separate(innerSeparator)); 
    audioItems.Select(x => x.Language).Separate(innerSeparator); 
} 

我幾乎可以肯定是停在那裏。您可以繼續下去:

public static IEnumerable<string> ProjectAndSeparateMany<T>(
    this IEnumerable<T> items, string separator, Func<T, object>... projections) 
{ 
    return projections.Select(projection => items.Select(projection) 
               .Separate(separator); 
} 

裏調用:

var audioItems = myObject.Audio.OrderBy(item => item.Key); 
row = audioItems.ProjectAndSeparateMany(innerSeparator, 
     x => x.Value, x => x.Format, x => x.Channels, x => x.Language).ToList(); 

...但在這一點上它是所以專家,我懷疑,我會永遠再次使用它。 ..

1

我想重構這個方法,使用指定的訪問器,或者可能傳遞一個委託,雖然我看不出如何工作。

你可以這樣使用對象語法和傳遞一個委託做的(這是假設你的.ValueMyValueType類型):

string NiceRefactor(MyObj myObject, Func<MyValueType, string> accessor) 
{ 
    return string.Join(innerSeparator, myObject.Audio.OrderBy(m => m.Key).Select(m => accessor(m.Value)); 
} 

利用這一點,你可以寫:

// "value" is some object with accessors like: format, channels, language 
row = new List<String> { 
    NiceRefactor(myObject, v => v.format), 
    NiceRefactor(myObject, v => v.channels), 
    NiceRefactor(myObject, v => v.language), 
    // ... 
} 
1

你可以做這樣的事情:

// "value" is some object with accessors like: format, channels, language 
row = new List<String> { 
    JoinProperties(myObject.Audio, innerSeparator, x => x.format), 
    JoinProperties(myObject.Audio, innerSeparator, x => x.channels), 
    JoinProperties(myObject.Audio, innerSeparator, x => x.language), 
// ... 
} 


... 


public string JoinProperties<TKey, TValue, TProperty>(IDictionary<TKey, TValue> dictionary, string separator, Func<TValue, TProperty> selector) 
{ 
    return string.Join(separator, dictionary.OrderBy(kvp => kvp.Key).Select(kvp => selector(kvp.Value))); 
} 
相關問題