【问题标题】:Create Queryable with correct ElementType from variable declared as the parent type of what the variable actually contains从声明为变量实际包含的父类型的变量创建具有正确 ElementType 的 Queryable
【发布时间】:2023-04-02 22:03:01
【问题描述】:

问题:

我有一个关于类型转换/泛型的问题 - 这是我的方法的签名:

public bool FilterMyModel<T>(T model)

T 是 Person 类型,而 model 是一个对象,它实际上是 ExtendedPerson 类型,是 Person 的子类。

我需要创建一个 IQueryable,它的 ElementType 为 ExtendedPerson,并包含在模型参数中传递的对象。**

我的尝试:

我尝试了这 3 种构造可查询对象的方法中的每一种,但在所有 3 种情况下,生成的可查询对象的 ElementType 都是 Person(如果我将该 IQueryable 输入过滤代码,它就不起作用)。

var query = new[] { model }.AsQueryable();
var query2 = new[] { model }.AsQueryable<T>();
var query3 = ((IEnumerable<T>)new[] { model }).AsQueryable<T>();

在像这样声明 IQueryable 之前,我还尝试将模型转换为 ExtendedPerson 类型,但出现错误“{”“MyNamespace.CastHelper.CastValue(System.Linq.IQueryable) 的最佳重载方法匹配”有一些无效参数"}" 就行 var modelCast = castHelper.CastValue(model);

//// Cast model (to handle Extended data types, e.g. ExtendedPerson, passed to this method as bast type, e.g. Person)
Type castHelperGenericBase = typeof(CastHelper<,>);
Type[] castTypeArgs = { typeof(T), model.GetType() };
Type castHelperType = castHelperGenericBase.MakeGenericType(castTypeArgs);
dynamic castHelper = Activator.CreateInstance(castHelperType);
var modelCast = castHelper.CastValue(model);

这是 CastHelper 的定义:

public class CastHelper<T,U> where U:T
{
    public IQueryable<U> CastValue(IQueryable<T> query) 
    {
        return (IQueryable<U>)query;
    }
}

有谁能帮助我弄清楚如何从具有 ExtendedPerson ElementType 的模型创建 IQueryable?

** 注意:我相信拥有 IQueryable 和 ElementType=ExtendedPerson 将使过滤工作 - 我真正知道的是,如果我来自数据库而不是来自模型对象,我将 ExtendedPersons 表查询为 IQueryable,IQueryable 的 ElementType 是 ExtendedPerson,然后如果我以动态方式将其转换为 IQueryable,则过滤工作

注 2:我知道很多人会质疑我是否应该做这样的事情 - 我想要这样做的原因是我们允许客户在现有应用程序中动态添加现有类型的扩展,并试图保持数量必须在运行时动态加载到 appdomain 的代码数量降至最低 - 因此,尝试使真正需要知道扩展对象的“真实”类型的代码部分使用反射来做到这一点,并在其他任何地方将它们作为父类型传递,并尽可能只为扩展类定义本身动态加载代码。

非常感谢您的帮助!!

【问题讨论】:

    标签: dynamic casting iqueryable


    【解决方案1】:

    回答这个问题的关键是知道如何关闭一个泛型方法。有两种方法可以解决此问题:

    1)我最初的问题是如何在接收它的方法中直接转换对象作为错误类型的参数。在这里回答:stackoverflow.com/questions/4925718/c-dynamic-runtime-cast

    2) 第二种选择是调用将参数作为 ExtendedPerson 而不是作为 Person 传递的方法 - 以下导致 T 被读取为正确的类型:

    var openGenericMethod = myFilteringClass.GetType().GetMethod("FilterMyModel");
    MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(model.GetType());
    closedGenericMethod.Invoke(viewFilter, new object[] { model });
    

    然后,在 FilterMyModel 中,我只需要使用 AsQueryable 的通用版本而不是非通用版本来定义可查询对象,如下所示:

    var query = new[] { model }.AsQueryable<T>();
    

    补充说明: - “myFilteringClass”是上面显示的“FilterMyModel”方法定义的类。 - 如果无法更改传递给 FilterMyModel 方法的 T 的值,我可以通过在同一个类中定义一个额外的泛型方法并以同样的方式从 FilterMyModel 调用它,从而轻松地将事物嵌套更深一层,效果一样

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-15
      • 2015-03-23
      • 2014-10-02
      • 2018-12-16
      • 2019-04-19
      • 1970-01-01
      相关资源
      最近更新 更多