2017-06-19 49 views
0

我想创建一个通用的方法,我想用于混合基于属性的对象的列表。或者,您可以提供一个列表对象列表,将一些组合并在一起。这工作正常,作为一个非泛型方法,当我手动编写代码的性能等c#如何使用通用IEnumerable上的包含<T>

方法头:

public static IEnumerable<T> MixObjectsByProperty<T>(
    IEnumerable<T> objects, 
    string propertyName, 
    IEnumerable<IEnumerable<T>> groupsToMergeByProperty = null) 

片段的方法体:

groups = 
    (from item in objects 
    let propertyInfo = item.GetType().GetProperty(propertyName) 
    where propertyInfo != null 
    group item by groupsToMergeByProperty 
     .FirstOrDefault(ids => ids.Contains(propertyInfo.GetValue(item, null))) 
     //.FirstOrDefault(ids => ids.Any(propertyInfo.GetValue(item, null))) 
     ?.First() 
     ?? propertyInfo.GetValue(item, null) 
    into itemGroup 
    select itemGroup.ToArray()) 
    .ToList(); 

正如你所看到的,我在IEnumerable<T>上使用contains方法时遇到了问题,因为propertyInfo.GetValue(item, null)正在返回一个对象。我已经试过各种铸造尝试,并且使用.Any()代替,但我已经撞了南墙:(

任何帮助将是巨大的,谢谢!

而且,让我知道,如果你需要更多的信息,但我猜想,在本质上,我需要知道的是如何使用<T>使用.Contains()

它们设置为相同类型?自定义IEqualityComparer

+0

为什么不直接将'GetValue'的结果转换为'T'? – Evk

+0

如果你可以将'T'约束到一个基类型或接口,它将会有很大的帮助。 –

+0

除非您将'T'转换为特定类型,否则它是已知的 – Rahul

回答

1

没有看到整个方法(因为你的类型签名清楚地表明它不是整个方法),这里是一个示例实现:

public class Ext 
{ 
    public static List<T[]> MixObjectsByProperty<T, TProp, U>(
     IEnumerable<T> source, 
     Expression<Func<T, TProp>> property, 
     IEnumerable<IEnumerable<U>> groupsToMix = null) 
     where T : class 
     where U : TProp 
    { 
     var prop = (PropertyInfo)(property.Body as MemberExpression)?.Member; 
     if (prop == null) throw new ArgumentException("Couldn't determine property"); 

     var accessor = property.Compile(); 

     var groups = 
      from item in source 
      let value = (U)accessor(item) 
      group item by 
       groupsToMix.FirstOrDefault((ids => ids.Contains(value))) 
      into itemGroup 
      select itemGroup.ToArray(); 
     return groups.ToList(); 
    } 
} 

对于神的爱停止传递属性名称和使用反射,其余的Linq使用华丽的表达系统,你也应该!

+1

好吧,哇,冷静下来:P感谢您的意见,它看起来不错 - 我没有意识到这一点。但是,您可以让您的linq返回列表吗?然后我可以充分测试这个潜在的解决方案 - 谢谢:) – user2439970

+0

@ user2439970肯定的事情,你去! – Clint

+1

为什么在世界上传递一个表达式,如果你只是要编译它。只需接受代表,如果你只想要一个代表。 – Servy

1

我已经试过各种铸造尝试

你试过这个吗?

.FirstOrDefault(ids => ids.Contains((T)propertyInfo.GetValue(item, null))) 

由于idsIGrouping<TKey, TElement>型,其中TElementT型的,你的情况,财产价值铸造T将允许比较。

+0

我尝试过,但有趣的是,我早些时候再次尝试,并与一些更多的调整,我有它的工作! :)我现在发布答案,以便其他人可以看到我做了什么,等等。 – user2439970

-1

好吧,所以我最终破解了它。我需要在我的通用方法头/签名中添加更多细节。

public static IEnumerable<T> MixObjectsByProperty<T, U>(
     IEnumerable<T> objects, string propertyName, IEnumerable<IEnumerable<U>> groupsToMergeByProperty = null) 
     where T : class 
     where U : class 
    { 
     ... 

注意,我添加类限制,允许我使用可空操作员等

而且身体变得(加入该铸造到正确的类型变量的PropertyValue后!):

  groups = 
       (from item in objects 
       let propertyInfo = item.GetType().GetProperty(propertyName) 
       where propertyInfo != null 
       let propertyValue = (U)propertyInfo.GetValue(item, null) 
       group item by 
        groupsToMergeByProperty 
         .FirstOrDefault(ids => ids.Contains(propertyValue)) 
         ?.First() 
        ?? propertyValue 
       into itemGroup 
       select itemGroup.ToArray()) 
       .ToList(); 
相关问题