繁体   English   中英

如何在泛型集合中强制转换对象?

[英]How to cast an object in generic collection?

我需要将一个对象转换为通用集合,看:

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);
    }
}

我怎样才能做到这一点?

观察:我需要使用此集合来调用另一个集合的except方法(该集合我以与currentCollection相同的方式获取,并使用anotherEntityProperty.GetValue(anotherEntity, null)

var itens = currentCollection.Except(anotherCollection);

动态类型使您可以使编译器和DLR在这里完成所有工作:

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

在执行时,这将为您完成所有反射工作,并选择最合适的type参数。

对于Except扩展方法,您只需要ICollection<T>实现的IEnumerable<T> 因此,您可以将属性转换为IEnumerable<object> (至少在T是引用类型的情况下)。

编辑:

如果确实需要,可以尝试通过反射对对象变量调用Except:

// 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;

您不能使用ICollection<some_type_determined_at_run_time> -编译器将无法为其生成任何有意义的代码。

如果类型与 ICollection<Base_Class>类型转换相关 ICollection<Base_Class>则应在4.0中工作 -错误...此类转换适用于IEnumerable(因为它的类型为“ out T”),但不适用于ICollection。

这不是直接回答您的问题,而是在评论中通过我们的讨论回答问题:

如何使用反射调用Except方法?

Except方法不是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);

这是乔恩·斯基特(Jon Skeet)的“简单方法”(C#4.0及更高版本):

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM