即使我有隐式运算符,类型转换也会失败

时间:2018-03-21 06:46:43

标签: c# .net casting

我编写了带隐式强制转换操作符的自定义类型

public class TcBool : TcDataTypeBase
{
    public TcBool() : base(1, false) { } //For somewhat reason without this callin new TcBool() fails
    public TcBool(bool value = false) : base(1, value) { }

    public static implicit operator bool(TcBool var) => (bool)var.Value;

    public static implicit operator TcBool(bool value) => new TcBool(value);
}

public abstract class TcDataTypeBase
{
    public readonly byte Size;
    public readonly object Value;

    public string Name { get; set; }
    public int IndexGroup { get; set; }
    public int IndexOffset { get; set; }

    internal TcDataTypeBase(byte size, object value)
    {
        Size = size;
        Value = value;
    }

    internal TcDataTypeBase(string name, byte size, object value) : this(size, value)
    {
        Name = name;
    }
}

然后,当我尝试使用PropertyInfo.SetValue()将其写入对象的布尔属性时,它会抛出一个异常,说它不能将TcBool转换为System.Boolean。

是否存在阻止反射机制使用隐式转换或者我遗漏了什么的东西?

3 个答案:

答案 0 :(得分:5)

编译器不知道它必须抛出任何东西,因为SetValue接受object,它与TcBool类型兼容,没有任何强制转换(事实上,你不能定义隐式强制转换运算符到祖先类型)。要强制演员,你可以这样做:

property.SetValue(instance, (bool)TcBool);

这将触发隐式转换运算符并创建一个布尔值,然后将其装入对象并传递给SetValue。

答案 1 :(得分:1)

编译器必须使用转换运算符。或者更确切地说,编译器指出可以应用转换并插入适当的调用。在运行时,这不会发生,并且您在这里留下了不兼容的类型,因为PropertyInfo.SetValue只需要object,所以从编译器的角度来看,不需要转换。 / p>

答案 2 :(得分:1)

免责声明:我意识到这可能有点过头,如果您在编译时不知道类型,则无法使用。

重要的是要知道隐式转换运算符被编译为名为"op_Implicit" 的方法,因此不会被自动调用

所以我创建了这个(相当长的)hacky helper方法,它将类型为TObject的对象转换为TTo类型的对象,同时考虑了隐式转换运算符:

public static object Convert<TObject, TTo>(TObject obj)
{
    IEnumerable<MethodInfo> implicitConversionOperators = obj.GetType()
                                                             .GetMethods()
                                                             .Where(mi => mi.Name == "op_Implicit");
    MethodInfo fittingImplicitConversionOperator = null;

    foreach (MethodInfo methodInfo in implicitConversionOperators)
    {
        if (methodInfo.GetParameters().Any(parameter => parameter.ParameterType == typeof(TObject)))
        {
            fittingImplicitConversionOperator = methodInfo;
        }
    }

    if (fittingImplicitConversionOperator != null)
    {
        return fittingImplicitConversionOperator.Invoke(null, new object[] {obj});
    }

    return (TTo) System.Convert.ChangeType(obj, typeof(TTo));
}

当然,它远非完美,但它可以像这样使用

propertyInfo.SetValue(this, Helper.Convert<TcBool, bool>(new TcBool(true)));

设置属性。当然,如果您在编译时不知道类型/不想要那么详细,您可以尝试dynamic等,因为它在其他答案中显示。