C# 使用转换运算符强制转换对象失败

C# 使用转换运算符强制转换对象失败,c#,generics,implicit-conversion,C#,Generics,Implicit Conversion,所以我有这个物体,比如说双容器 public struct DoubleContainer { private readonly double _value; private DoubleContainer(double value) { _value = value; } public static implicit operator double(DoubleContainer 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;
}
如果我使用dynamic,我可以让它工作:

public double GetDouble(Object input)
{
   return (double)(dynamic)input;
}
这个解决方案的问题是VisualStudio将(动态)显示为灰色,因为它应该是冗余的,所以有人可能会删除它。另外,我不知道在代码库中是否还有其他地方会出现同样的问题


对于DoubleContainer的实现,我能做些什么呢?是什么让我的第一个GetDouble()实现工作?我尝试添加另一个从Object到DoubleContainer的隐式转换运算符,但“不允许向基类或从基类进行用户定义的转换”…

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

当你在中间插入<代码>动态< /代码>时,编译器将生成“如果这个引用有一个操作符加倍,调用它”,那么它就起作用了。 因此,只要您将
系统对象
强制转换为double,它实际上就无法工作,而@juharr建议的代码经过稍微修改后,可以工作:

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

编辑:根据@SergiyKlimkov comment修改代码,您无法使其正常工作,因为您只能将装箱结构(这是您使用
(double)input所做的)取消装箱到确切的未装箱类型,原因最好由Eric Lippert在本文中描述。因此,无论何时执行
(double)someObject
-只有当object实际上是一个
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);
}

为什么要将一个
double
封装到一个类中,只是为了将其强制转换为
对象
?如果这只是一个示例,并且您有一个更复杂的类,具有有效的强制转换为
double
,那么为什么要将其强制转换为
对象
。基本上,如果您有这些类型的强制转换问题,您应该真正查看您的设计。我同意我们的代码这方面的设计是有问题的。不幸的是,在发行版的这一点上重新设计是不可能的。我只是想为一个bug找到一个修复方法,希望它有点健壮,而不是超级黑客。@Ash该类本身就是超级黑客。你可以做一些类似于
var dc=input as DoubleContainer;if(dc!=null)return(double)dc;else返回(double)input;
我想这真的取决于您希望传递给
GetDouble
的内容。“我能对我的DoubleContainer实现做些什么吗?什么能让我的第一个GetDouble()实现工作?”-不,没有。DoubleContainer是一个结构。所以“作为DoubleContainer输入”“不会编译。它需要替换为“(DoubleContainer)input”。你链接的那篇文章解释得很好。@Ash:很高兴听到这个消息!这是一个关于演员阵容的常见问题。