是否可以在c#中使用在运行时创建的类型的隐式转换?

时间:2016-02-08 13:12:35

标签: c# reflection casting reflection.emit typebuilder

我使用Reflection.Emit在运行时创建类型。问题是每当我实例化新类型的实例时,我都必须使用objectdynamic,因为在编译时类型是不可知的。除了在分配期间我希望另一种类型隐式地转换为新类型时,这工作正常。该变量愉快地采用新值及其对应的类型,而不尝试强制转换为其当前类型。

有没有办法创建一个允许隐式转换的新创建类型的变量?我非常高兴放弃编译时检查,但我希望至少在运行时尝试这些演员。

编辑:

这是一个让它更清晰的例子。当您在编译时知道类型时会发生这种情况:

MyClass a;
//this calls the implicit cast operator and 'a' stays of the same type
a = 5;

如果你不这样做会发生这种情况:

Type t = CreateTypeUsingTypeBuilder();
object a = Activator.CreateInstance(t);
//this does not call the implicit cast operator and 'a' just becomes in integer
a = 5;

此外,我对这种行为并不会感到惊讶,也不会问为什么会这样。我问是否有任何解决方法来实现在运行时检查隐式运算符所需的行为。

2 个答案:

答案 0 :(得分:2)

为了理解为什么这是不可能的,至少不是直接的,我们需要首先理解隐式转换运算符是如何工作的。

当你写这样的东西时

MyNumericType x = new MyNumericType(123);
double y = x;

编译器意识到xy属于不同的类型,并搜索MyNumericType以查看是否定义了隐式转换运算符:

public static implicit operator double(MyNumericType n) {
    return n.doubleValue;
}

找到运算符后,编译器会调用它,就好像它是常规的static方法(which it is)。

使用在运行时生成的类型时,也应该在运行时生成转换。例如,如果你这样做

private static Func<object,object> MakeConverter(Type t1, Type t2) {
    var p = Expression.Parameter*(typeof(object));
    var eFrom = Expression.Convert(p, t1);
    var eTo = Expression.Convert(eFrom, t2);
    var res = Expression.Convert(eTo, typeof(object));
    var lambda = Expression.Lambda<Func<object,object>>(res, new[] { p });
    return (Func<object,object>)lambda.Compile();
}

使用此方法,您可以执行此操作:

Type runtimeType1 = ...
Type runtimeType2 = ...
var converter = MakeConverter(runtimeType1, runtimeType2);
object objRuntimeType1 = ...
object objRuntimeType2 = converter(objRuntimeType1);

答案 1 :(得分:0)

如果我想在这个上下文中想要在运行时为已知类型创建包装类,那么我可以尝试一些想法。

一种是在包装器类型中添加一个参数化构造函数,它将包装类型的对象作为参数,然后使用该对象初始化包装器对象(就像在隐式转换运算符中一样)。然后,知道你可以使用例如一个整数作为构造函数参数,你可以这样做:

Type t = CreateTypeUsingTypeBuilder();
object a = Activator.CreateInstance(t, 5);

这将在类型中搜索可以使用给定对象调用的构造函数。如果找不到匹配的公共构造函数,则可能会获得MissingMethodException

另一个想法是为运行时构建的类型创建接口或抽象基类型,这需要派生类实现某种转换方法。从此抽象类派生构建类型或使它们实现接口时,可以将使用Activator创建的对象强制转换为该类或该接口,然后正常调用转换方法。如果您将界面设为通用,则可以有多种不同的转换实现。

public interface IMyWrapper<T>
{
    IMyWrapper<T> Convert(T value);
}

虽然无法隐式使用隐式运算符,但我认为您可以实现以某种其他方式将整数转换为内置类型的最终目标,包括上面提到的一个或另一个。