从运行时泛型类型的泛型方法检索集合

时间:2020-06-17 09:24:27

标签: c# .net reflection

我有一个通用方法

var propertyResolverMethod = _propertyResolver
    .GetType()
    .GetMethod(
        nameof(_propertyResolver.GetEntities),
        new[] { typeof(string), typeof(string) })
    ?.MakeGenericMethod(_itemType);

和调用

var recommendedItems = propertyResolverMethod
    ?.Invoke(
        _propertyResolver,
        new object[] { itemId, ResolvedCollectionId });

它在编译时返回一个对象,但是在运行时,它返回IQueryable<Item>,该项目是_itemType的项目,我们仅在运行时才能找到其类型,但是我知道它具有一个集合我需要获取的Item.RelatedItems内部。已尝试将其强制转换为动态,但不适用于我的情况,我知道可以通过表达式解决。

应该是可迭代的

var itemIds = recommendedItems?.Select(i => i.RelatedItems.Select(s => s.ItemID));

但是没有适当的转换是不可能的

1 个答案:

答案 0 :(得分:0)

嗯..

因此,如果我正确理解了您,您就会知道此方法将返回一个IQueryable<Item>,其中Item是先前存储在_itemType中的类型,并且您也知道该类型始终会定义一个事实RelatedItems依次是IEnumerable<T>IQueryable<T>,其中T定义了ItemID

是否存在所有可能的_itemTypes都继承自RelatedItems的类型?如果是这样,您可以尝试将其投射...

否则,您可以做更多反射魔术: 如果您知道结果是IQueryable<TItem>,则可以使用Reflection提取RelatedItems的属性获取器,然后将 that 传递给Select函数(可以通过投射到IQueryable<object>或再次使用...反射。

但是说实话,这将是一种非常非常肮脏的方式,而我只会在万不得已的情况下这样做。

我现在的第一个本能是尝试重构包含的类(_itemType提示我这是一个成员字段),所以它也是通用的(如果需要,可以从非通用类继承) ),因此该类通过其自己的type参数知道该类型。

另一种解决方案是具有以下功能:

private <Type of itemIDs> GetRelatedItemIds<TItem>(object source) {
 return ((IQueriable<TItem>)source)?.Select(i => i.RelatedItems.Select(s => s.ItemID));
}

现在通过反射获得该方法,并在其上使用MakeGenericMethod(_itemType),然后将其与您的结果一起调用。

请注意,当前选择将返回一个嵌套的可枚举/可查询的列表,每个条目都是ItemID的列表。如果不想这样做,请使用SelectMany而不是第一个Select,它会自动将内部枚举/可查询对象连接起来。

我希望这可以帮助您找到解决方案。