使用 < 和 > 运算符时支持哪些隐式转换?

8

我有一个结构体:

public struct Decibel
{
    public readonly double Value;

    public Decibel (double value)
    {
        Value = value;
    }

    public static implicit operator Decibel (double decibels)
    {
        return new Decibel (decibels);
    }

    public static implicit operator double (Decibel decibels)
    {
        return decibels.Value;
    }
}

现在我可以做到:

bool x = new Decibel (0) < new Decibel (1);

编译器似乎足够智能,可以将 Decibel 转换为 double,然后使用双精度的 < 操作符?

我有一个名为 Duration 的不同的 struct,它包装了 TimeSpan。它为 TimeSpanDuration 提供了隐式转换,但是 <> 操作符对它不起作用。

C# 只能识别原始类型之间的转换吗?


这里有与之相关的Eric Lippert信息: http://stackoverflow.com/a/8529811/106159 - Matthew Watson
"implicit" 转换使得出现错误变得非常容易。它们应该被谨慎地少用。而且对于原始类型的隐式转换只会带来麻烦。 - H H
@HenkHolterman:我知道,我正在小心地尝试使用它 :) - apocalypse
1个回答

3
首先请注意,C#最多允许一种类型之间的隐式用户定义转换。
因此,当您比较两个Decibel实例时,编译器会看到它可以使用用户定义的隐式转换将Decibel转换为double来进行比较。
然而,当您比较两个Duration实例时,编译器找不到任何单个隐式转换可用于允许比较。编译器不会考虑任何类型的用户定义比较运算符,这些类型可以隐式转换为该类型。它只会查找可以将类型隐式转换为其任何类型的内置比较运算符。
因此,即使TimeSpan提供了一个理论上可以使用的用户定义比较运算符,编译器也不会使用隐式转换为TimeSpan,并且即使TimeSpan类提供了隐式转换为double,编译器也不会使用它,因为它最多只会考虑一种链式隐式转换中的一种用户定义转换。
换句话说,给定以下结构:
public struct Number
{
    public readonly double Value;

    public Number(double value)
    {
        Value = value;
    }

    public static implicit operator Number(double duration)
    {
        return new Number(duration);
    }

    public static implicit operator double(Number number)
    {
        return number.Value;
    }
}

public struct NumberWrapper
{
    public readonly Number Value;

    public NumberWrapper(Number value)
    {
        Value = value;
    }

    public static implicit operator NumberWrapper(Number duration)
    {
        return new NumberWrapper(duration);
    }

    public static implicit operator Number(NumberWrapper number)
    {
        return number.Value;
    }
}

这段代码将会被编译:
bool x = new Number(1) < new Number(2);

当然,这也会发生变化:
Number n1 = new NumberWrapper(1);
Number n2 = new NumberWrapper(2);
bool z = n1 < n2;

但这个不会:
bool y = new NumberWrapper(1) < new NumberWrapper(2);

因为NumberWrapper没有对任何支持<的类型进行隐式转换,所以需要进行进一步的隐式转换。

请注意,所有原始数值和枚举类型(例如char、short、int、long、float、double、decimal、enum)都提供内置比较运算符。所有其他类型都只能提供用户定义的比较运算符。

用户定义的比较运算符应该像这样:

public static bool operator < (MyType lhs, MyType rhs) ...

也许你应该解释一下“用户定义比较运算符”和“内置比较运算符”的区别,以使其更清晰明了。 - Magnus
@Magnus:是的,TimeSpan的运算符是内置的吗?还是基本类型的运算符是内置的? - apocalypse
@zgnilec 这些运算符仅适用于原始类型(正如我在答案末尾所述)。 - Matthew Watson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接