6

次のタイプがあるとします。

struct MyNullable<T> where T : struct
{
    T Value;

    public bool HasValue;

    public MyNullable(T value)
    {
        this.Value = value;
        this.HasValue = true;
    }

    public static implicit operator T(MyNullable<T> value)
    {
        return value.HasValue ? value.Value : default(T);
    }
}

そして、次のコードスニペットをコンパイルしてみてください。

MyNullable<int> i1 = new MyNullable<int>(1);
MyNullable<int> i2 = new MyNullable<int>(2);

int i = i1 + i2;

これはうまくコンパイルされ、エラーは発生しませんでした。i1とi2は整数にキャストし、加算が評価されます。

しかし、次のタイプがある場合:

struct Money
{
    double Amount;
    CurrencyCodes Currency; /*enum CurrencyCode { ... } */

    public Money(double amount, CurrencyCodes currency)
    {
        Amount = amount;
        Currency = currency;
    }

    public static Money operator + (Money x, Money y)
    {
        if (x.Currency != y.Currency)
            // Suppose we implemented method ConvertTo
            y = y.ConvertTo(x.Currency); 

        return new Money(x.Amount + y.Amount, x.Currency);
    }
}

別のコードスニペットをコンパイルしてみてください。

MyNullable<Money> m1 = 
   new MyNullable<Money>(new Money(10, CurrenciesCode.USD));
MyNullable<Money> m2 = 
   new MyNullable<Money>(new Money(20, CurrenciesCode.USD));

Money m3 = m1 + m2;

そして、なぜコンパイラが「エラーCS0019:演算子'+'をタイプ'MyNullable<Money>'および'MyNullable <Money>'」のオペランドに適用できないのかという質問がありますか?

4

2 に答える 2

10

これは興味深い質問です...Decimalたとえば、は動作しますが、動作しませんTimeSpan。どちらも適切な.NETタイプであり(floatプリミティブであるなどとは異なります)、両方とも+演算子があります。奇妙!

もちろん、次の方法で腕をひねることができます。

Money m3 = (Money)m1 + (Money)m2;

もちろん、それを使用するだけNullable<T>で無料で動作します。さらに、コンパイラとランタイム(ボクシング)のサポートが受けられます。ここで使用しない理由はありNullable<T>ますか?

仕様を見てみましょう。MyNullable<T>暫定的に、オペレーターを;に昇格させることを考えるかもしれません。通常Nullable<T>の場合、C#コンパイラは、型でサポートされている演算子に「リフトされた」演算子を提供しますが、自分でそれを行うことはできません。あなたができる最善のことは、すべての明白なものを提供し、タイプがそれをサポートすることを願っています; -pジェネリックスで演算子にアクセスするには、ここを参照してください。ここから無料でダウンロードできます

適切な「解除された」チェックを適用することをお勧めします。

x + y => (x.HasValue && y.HasValue)
          ? new MyNullable<T>(x.Value + y.Value)
          : new MyNullable<T>();

アップデート

異なる処理は、14.2.4(ECMA 334 v4)の「加算演算子」に関連しているように見えます。14.2.4(同じ)「二項演算子のオーバーロード解決」、事前定義された演算子は特別な言及を取得します。しかし、私はそれを完全に理解しているとは言いません。

于 2008-12-26T11:57:57.807 に答える
9

Marc は正しい行にいます - C# 3.0 仕様のセクション 7.2.4 - Binary Operator Overload Resolution です。

基本的に手順は次のとおりです。

  • X と Y の両方が である "X + Y" の実装を解決する必要がありMyNullable<Money>ます。
  • セクション 7.2.5 (ユーザー定義演算子の候補) を見ると、MyNullable<T>+ がオーバーロードされていないため、最終的に空のセットになります。
  • 7.2.4 では、候補となる演算子のセットは、組み込みの + の二項演算子のセットです。つまり、int+int、decimal+decimal などです。
  • その後、7.4.3 のオーバーロード解決規則が適用されます。これはMyNullable<int> + MyNullable<int>、各引数が暗黙的にint- に変換されるため機能しますが、 が候補演算子のセットに含まれていないため機能MyNullable<Money> + MyNullable<Money>ません。Money + Money
于 2008-12-27T12:16:54.947 に答える