2012-03-23 28 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))); 
} 
相关问题