2017-06-19 132 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(); 
相關問題