2012-03-01 54 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