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

Casting an object with a conversion operator fails

所以我有这个对象,比如 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);
    }
}

除了将它作为对象传递给函数的情况外,几乎在所有情况下都可以按预期进行转换。

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

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

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

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

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

我可以对 DoubleContainer 的实现做些什么来使我的第一个 GetDouble() 实现正常工作?我尝试添加另一个从 Object 到 DoubleContainer 的隐式转换运算符,但是 "user-defined conversions to or from a base class are not allowed"...

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

当你在中间插入 dynamic 时,编译器会生成类似“如果这个引用有一个双精度运算符,调用它”这样的东西,所以它有效。

因此,只要将 System.Object 转换为双精度数,它实际上就无法工作,而@juharr 建议的代码稍作修改后就可以工作:

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

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

您无法使其工作,因为您只能将已装箱的结构(这就是您使用 (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);
}