2012-03-01 82 views
1

我需要將對象轉換爲泛型集合,請看:如何投射泛型集合中的對象?

var currentEntityProperties = currentEntity.GetType().GetProperties(); 

foreach (var currentEntityProperty in currentEntityProperties) 
{ 
    if (currentEntityProperty.PropertyType.GetInterfaces().Any(
       x => x.IsGenericType && 
       x.GetGenericTypeDefinition() == typeof(ICollection<>))) 
    { 
     var collectionType = currentEntityProperty.PropertyType.GetInterfaces().Where(
           x => x.IsGenericType && 
           x.GetGenericTypeDefinition() == typeof(ICollection<>)).First(); 

     var argumentType = collectionType.GetGenericArguments()[0]; 

     // now i need to convert the currentEntityProperty into a collection, something like that (this is wrong, so, what is thr right way?): 
     var currentCollection = (ICollection<argumentType.GetType()>)currentEntityProperty.GetValue(currentEntity, null); 
    } 
} 

我怎麼能這樣做呢?

觀測值:我需要與此集合調用方法,除了與另一個集合(這個集合我與currentCollection以同樣的方式獲得,具有anotherEntityProperty.GetValue(anotherEntity, null)

var itens = currentCollection.Except(anotherCollection); 
+2

之後你會怎麼做?如果您可以更多地瞭解更廣泛的背景,我們可以提供一種替代方法。 – 2012-03-01 17:03:41

+0

好的!編輯的問題。 – 2012-03-01 17:07:48

+1

你不知道'anotherCollection'的類型嗎?你從哪裏得到?你能否早些時候用反射進行單一的通用呼叫?如果您使用的是C#4,動態類型也可以使這更簡單。 – 2012-03-01 17:09:15

回答

4

動態類型可讓您的編譯器和DLR這裏做所有的工作:

dynamic currentCollection = ...; 
dynamic anotherCollection = ...; 
dynamic items = Enumerable.Except(currentCollection, anotherCollection); 

在執行時,這將爲您做所有的反射工作,並選擇最合適的類型參數。

+0

這太漂亮了! = P - 我不知道這個關鍵字是'dynamic'。所以,謝謝喬恩! – 2012-03-01 18:09:51

+0

@ViniciusOttoni:這是值得學習的,所以你可以在適度的情況下使用它*。請注意,如果「執行時編譯器」無法解決該做什麼,這將最終拋出一個綁定異常。 – 2012-03-01 18:14:02

+0

是的,我看到危險,如果它沒有適度使用,但如果你知道你在做什麼,這可以是美麗=)。 – 2012-03-01 18:18:08

0

不能使用ICollection<some_type_determined_at_run_time> - 編譯將無法爲其生成任何有意義的代碼。

如果類型應該在4.0 工作有關鑄造ICollection<Base_Class> - 錯了......這樣的鑄造工程的IEnumerable(因爲它有「出T」類型),但不會對ICollection的。

+1

你對Base_Class有什麼意思? Base_Class是誰?因爲我不知道在'argumentType'中會得到什麼類型。 – 2012-03-01 17:16:04

+0

我以某種方式決定,如果您的集合包含Derived:MyBase類型,那麼您可以將它從ICollection 轉換爲ICollection ,這是不正確的 - 已編輯。 – 2012-03-01 17:24:10

1

對於Except擴展方法,您只需要一個IEnumerable<T>,其中ICollection<T>實現。所以你可以投你的財產IEnumerable<object>(至少如果T是參考類型)。

編輯:

如果你真的想,你可以試試這個反射除非對象變量調用:

// x and y are your object variables of the collections, 
// argumentType is the generic type you determined 
    var methods = from m in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) 
       where m.ContainsGenericParameters 
       && m.Name == "Except" 
       && m.GetParameters().Count() == 2 
       && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
       && m.ReturnType.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
       select m; 
    var method = methods.First(); 
    IEnumerable things = method.MakeGenericMethod(new Type[] { argumentType }).Invoke(null, new [] { x, y }) as IEnumerable; 
+0

T可以是字符串,int,我創建的類型... – 2012-03-01 17:18:41

+0

非泛型'ICollection'不實現泛型'IEnumerable ' – phoog 2012-03-01 17:30:37

+0

泛型ICollection 確實。 )括號只是缺少;) – Botz3000 2012-03-01 17:34:14

0

這並不直接回答你的問題,而是回答了這個問題從我們在評論中討論:

How can I call the Except method using reflection?

的除方法不是的ICollection<T>一員,這就是爲什麼你GetMethod調用返回null。相反,它是在靜態類型System.Linq.Enumerable上定義的擴展方法。要用反射來調用它,你必須把它當作一個靜態方法。事情是這樣的:

// there are two overloads of Except and I'm too lazy to construct the type parameters to get the correct overload 
var methods = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public); 
var exceptMethod = methods.Where(m => m.Name.Equals("Except") && m.GetParameters().Lengh == 2).Single(); 

object[] arguments = new [] { currentCollection, anotherCollection }; 
object items = exceptMethod.Invoke(null, arguments); 

這裏的喬恩斯基特的 「簡單的方法」(C#4.0和更高版本):

dynamic items = Enumerable.Except((dynamic)currentCollection, (dynamic)anotherCollection); 
+0

'methods'的計數是0. – 2012-03-01 17:58:10

+0

@ViniciusOttoni我在複製和粘貼後忘記了更改BindingFlags參數。現在已經修復了。我也忘了給'Single()'添加一個調用,它也是固定的。 – phoog 2012-03-01 17:59:45