显式转换为已定义的类型会抛出`InvalidCastException`

Clo*_*use 6 c# casting

我有一些使用显式强制转换操作定义的自定义包装器类型:

private class A
{
    private readonly int _value;

    public A(int value)
    {
        _value = value;
    }

    public int Value { get { return _value; } }
}

private class B
{
    private readonly int _value;

    private B(int value)
    {
        _value = value;
    }

    public int Value { get { return _value; } }

    public static explicit operator B(A value)
    {
        return new B(value.Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

以下工作正常:

B n = (B)new A(5);
Run Code Online (Sandbox Code Playgroud)

这不是:

B n = (B)(object)new A(5);

// Throws System.InvalidCastException:
// Unable to cast object of type 'A' to type 'B'
Run Code Online (Sandbox Code Playgroud)

...这里发生了什么?
我被限制为object首先使用强制转换- 实际的强制转换是在通用库代码中的其他地方执行的(所以它是形式return (TOutput)(object)input;,而dynamic不是一个选项)

das*_*ght 7

第一个代码片段工作的原因是你看到的不是 "直接"强制转换:它是一个显式转换运算符的调用.这个操作是明确定义的,并且完全按照编码的方式工作:一个全新的对象B是根据其A价值构建的.C#有足够的信息来确定要调用显式运算符,因为new A(5)type匹配operator B(A value)参数的类型.

object但是,一旦添加了强制转换,编译器就会进行真正的强制转换.C#不再具有适用的用户定义转换运算符,因此它执行类型检查,确定A不可转换为B,并抛出异常.

有一种方法可以让它在没有dynamic构建和编译动态lambda的情况下工作,如下所示:

private static B ConvertFromObject(object a) {
    if (a == null) return null;
    var p = Expression.Parameter(typeof(object));
    var c1 = Expression.Convert(p, a.GetType());
    var c2 = Expression.Convert(c1, typeof(B));
    var e = (Func<object,B>)Expression.Lambda(c2, p).Compile();
    return e(a);
}
Run Code Online (Sandbox Code Playgroud)

演示.

您可以通过a运行时类型缓存已编译的lambdas,以节省每次运行该方法时编译新表达式的成本.