从声明为变量实际包含的父类型的变量中使用正确的 ElementType 创建 Queryable
Create Queryable with correct ElementType from variable declared as the parent type of what the variable actually contains
问题:
我有一个关于类型转换/泛型的问题 -
这是我的方法的签名:
public bool FilterMyModel<T>(T model)
T 是 Person 类型,model 是一个实际上属于 ExtendedPerson 类型的对象,是 Person class 的子对象。
我需要创建一个 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 类型,但是在 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;
}
}
有谁能帮我弄清楚如何从 ElementType 为 ExtendedPerson 的模型创建 IQueryable 吗?
** 注意:我相信具有 ElementType=ExtendedPerson 的 IQueryable<> 将使过滤工作——我真正确定的是,如果我来自数据库而不是来自模型对象,然后我将 ExtendedPersons table 查询到 IQueryable 中,IQueryable 的 ElementType 是 ExtendedPerson,然后如果我以动态方式将其转换为 IQueryable,则过滤有效
注意 2:我知道很多人会质疑我是否应该做这样的事情 - 我想这样做的原因是我们允许客户动态地向现有应用程序中的现有类型添加扩展,并试图保持必须在运行时动态加载到 appdomain 的代码量降至最低 - 因此尝试使真正需要知道扩展对象的 "true" 类型的代码部分使用反射来做到这一点,以及其他任何地方将它们作为父类型传递,并在可能的情况下仅为扩展 class 定义本身动态加载代码。
非常感谢您的帮助!!
回答这个问题的关键是知道如何关闭泛型方法。有 2 个选项可以解决这个问题:
1) 我最初的问题是问如何直接将接收对象的方法内部的对象转换为错误类型的参数。在这里回答:whosebug.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" 是class,其中定义了上面显示的"FilterMyModel" 方法。
- 如果无法更改传递给 FilterMyModel 方法的 T 的值,我可以通过在同一 class 中定义一个额外的通用方法并从 FilterMyModel 中调用它来轻松地更深层次地嵌套事物同样的方法,同样的效果
问题:
我有一个关于类型转换/泛型的问题 - 这是我的方法的签名:
public bool FilterMyModel<T>(T model)
T 是 Person 类型,model 是一个实际上属于 ExtendedPerson 类型的对象,是 Person class 的子对象。
我需要创建一个 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 类型,但是在 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;
}
}
有谁能帮我弄清楚如何从 ElementType 为 ExtendedPerson 的模型创建 IQueryable 吗?
** 注意:我相信具有 ElementType=ExtendedPerson 的 IQueryable<> 将使过滤工作——我真正确定的是,如果我来自数据库而不是来自模型对象,然后我将 ExtendedPersons table 查询到 IQueryable 中,IQueryable 的 ElementType 是 ExtendedPerson,然后如果我以动态方式将其转换为 IQueryable,则过滤有效
注意 2:我知道很多人会质疑我是否应该做这样的事情 - 我想这样做的原因是我们允许客户动态地向现有应用程序中的现有类型添加扩展,并试图保持必须在运行时动态加载到 appdomain 的代码量降至最低 - 因此尝试使真正需要知道扩展对象的 "true" 类型的代码部分使用反射来做到这一点,以及其他任何地方将它们作为父类型传递,并在可能的情况下仅为扩展 class 定义本身动态加载代码。
非常感谢您的帮助!!
回答这个问题的关键是知道如何关闭泛型方法。有 2 个选项可以解决这个问题:
1) 我最初的问题是问如何直接将接收对象的方法内部的对象转换为错误类型的参数。在这里回答:whosebug.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" 是class,其中定义了上面显示的"FilterMyModel" 方法。 - 如果无法更改传递给 FilterMyModel 方法的 T 的值,我可以通过在同一 class 中定义一个额外的通用方法并从 FilterMyModel 中调用它来轻松地更深层次地嵌套事物同样的方法,同样的效果