c# - 与泛型一起使用时,Expression.Convert(..., someGenericType) 会抛出 ArgumentException

标签 c# generics lambda expression expression-trees

我有这个方法,使用Expression s 创建字段 setter/getter :

public static Func<object, T> CreateFieldValueGetter<T>(this Type declaringType, FieldInfo fieldToGet) {
    var paramExp = Expression.Parameter(typeof(object));
    // ArgumentException if declaringType describes generic-type:
    var cast = Expression.Convert(paramExp, declaringType);
    var body = Expression.Field(cast, fieldToGet);
    return Expression.Lambda<Func<object, T>>(body, paramExp).Compile();
}

它工作得很好,直到我给它一个通用类型,比如:

class DataErrorNotifyingViewModelBase<TErr> : ViewModelBase, INotifyDataErrorInfo 
    where TErr : struct, IConvertible, IComparable, IFormattable
{
    // ...
}

这样:

var vm = new DataErrorNotifyingViewModelBase<MyErrorsTypeEnum> ();
var type = vm.GetType();
// ArgumentException:
var getter = type.CreateFieldValueGetter<PropertyChangedEventHandler>(type.GetField("PropertyChanged"));

这是我得到的异常:

Exception thrown: 'System.ArgumentException' in System.Core.dll

Additional information: Type GuiHelpers.DataErrorNotifyingViewModelBase`1[TErr] is a generic type definition

虽然简单的转换工作:

var vm = new DataErrorNotifyingViewModelBase<PrintDialogError>();
var obj = (object) vm;

那么我如何为它提供通用类型呢?我是否仅限于非通用类型?

编辑 - 解决方案:

Kaveh Hadjari捕获了它:

传递 t = typeof (Dictionary<T, int>)会提高ArgumentException , 作为 t.GetGenericArguments()[0].IsGenericParametertrue (尽管 t.GetGenericArguments()[1].IsGenericParameterfalse !)

传递类型 t = typeof (Dictionary<int, int>)工作正常,因为 t.GetGenericArguments() 中没有元素数组有 IsGenericParameter == true

最佳答案

通用类型是许多不同专用类型的模板,在运行时通用类型和“实例化”类型之间存在差异。调用 Expression.Convert 失败的一个可能原因可能是您为其提供了通用版本的类型,而不是带有类型变量集的专用版本。

更新:我想有一个很好的理由让这个方法永远不能用于泛型类型。考虑这种情况,如果类型变量用作泛型类中字段的类型。由于类型大小(引用、 bool 、短、整型、长等)可能是可变的,这意味着它可以以可变方式偏移泛型类的不同特化中其他字段的内存地址。如果所有变量都未设置,您如何提前知道哪个字段长度以及地址偏移量?你不能,因此我们无法确定我们可能想要为其创建 getter 的字段的地址。唯一的解决方案是实际创建一个 getter,它依赖于对调用 getter 的每个对象使用反射,这会产生比想象的更高的成本,如果您对该解决方案感到满意,您也可以使用一个方法使用反射获取字段的值,而不首先实际创建这些 getter。

关于c# - 与泛型一起使用时,Expression.Convert(..., someGenericType) 会抛出 ArgumentException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33861052/

相关文章:

c# - 将更改后的元素保存回 XML 文件

java - 使用泛型时我应该做什么来测试 EasyMock 对象?易模拟

c# - 如何定义可以返回 DataTable 或 List <T> 的方法?

c# - C# 是适用于大型项目的可行语言吗?

非焦点形式的 C#/WPF 热键(如 launchy)

extension-methods - 将泛型扩展方法限制为基本类型和字符串

class - 从协议(protocol)调用类方法作为参数

java - Optional ifPresent() 可以用在更大的表达式中以减轻对 get() 的调用吗?

c++ - 在C++线程对象中重新绑定(bind)*this, move 构造函数, move 赋值

c++ - lambda 如何捕获自身以进行异步调用?