使用转换运算符转换对象失败

时间:2017-10-20 18:20:59

标签: c# generics implicit-conversion

所以我有这个对象,比如DoubleContainer。

public struct DoubleContainer
{
    private readonly double _value;

    private DoubleContainer(double value)
    {
        _value = value;
    }

    public static implicit operator double(DoubleContainer doubleContainer)
    {
        return doubleContainer._value;
    }

    public static DoubleContainer Create(double value)
    {
        return new DoubleContainer(value);
    }
}

在几乎所有情况下,它都可以按预期运行,除非它作为Object传递给函数。

如果我传入DoubleContainer,则以下代码生成InvalidCastException:

public double GetDouble(Object input)
{
    return (double)input;
}

如果我使用动态,我可以让它工作:

public double GetDouble(Object input)
{
   return (double)(dynamic)input;
}

我对这个解决方案的问题是Visual Studio灰色(动态),因为它应该是多余的,所以有人可能会删除它。此外,我不知道代码库中是否还有其他地方可能会出现同样的问题。

我对DoubleContainer的实现有什么办法可以让我第一次实现GetDouble()工作吗?我尝试将另一个隐式转换运算符从Object添加到DoubleContainer,但是“不允许用户定义到基类的转换”....

2 个答案:

答案 0 :(得分:3)

你不能使它工作,因为你只能将装箱的结构(这是你用(double) input做的那样)取消对确切的未定类型,因为这个article中最好描述的原因是埃里克利珀特。因此,无论何时执行(double) someObject - 只有当对象实际上是double而不是int,而不是float,而不是DoubleContainer时,它才会起作用。如果您期望其他类型 - 您可以更好地使用Convert.ToDouble。要使用您的类型,您需要它来实现IConvertible

public struct DoubleContainer : IConvertible
{
    private readonly double _value;

    private DoubleContainer(double value)
    {
        _value = value;
    }

    public static implicit operator double(DoubleContainer doubleContainer)
    {
        return doubleContainer._value;
    }

    public static DoubleContainer Create(double value)
    {
        return new DoubleContainer(value);
    }

    public double ToDouble(IFormatProvider provider) {
        return _value;
    }

    public bool ToBoolean(IFormatProvider provider) {
        // delegate to your double
        return ((IConvertible) _value).ToBoolean(provider);
    }

    // ... rest is skipped ...

然后它将与

一起使用
public double GetDouble(Object input)
{
    return Convert.ToDouble(input);
}

答案 1 :(得分:1)

当将对象转换为double时,编译器不知道它应该调用现有的operator double,因此它不会向用户定义的运算符double插入任何调用。

当您在中间插入dynamic时,编译器将生成类似"如果此引用具有运算符double,则调用它`,这样就可以了。

所以,只要你将System.Object转换为double,它实际上就无法工作,而@juharr建议稍微修改的代码将起作用:

public double GetDouble(Object input)
{
    if (input is DoubleContainer)
    {
        var dc = (DoubleContainer)input; 
        return (double)dc;
    }
    return (double)input;
}

编辑:根据@SergiyKlimkov评论修改代码