1

私は、このような SO に関する多くの質問があることを知っています
"Operator 'whatever' cannot be applied to operands of type 'T'(++、+=、<= など)。

このコードがあるとしましょう

public class GenericCls<T> where T : struct
{
    public static T AddValues(params T[] values)
    {
        T sum = default(T);
        if (values != null)
        {
            for (int i = 0; i < values.Length; i++)
            {
                sum += values[i];
            }
        }
        return sum;
    }
}

型構造体と値型を作成したにもかかわらず、エラーが発生します Operator '+=' cannot be applied to operands of type 'T' and 'T'

微妙にValueType制約を適用しようとすると、次のように表示されます Constraint cannot be special class 'System.ValueType'

forループでパラメーターをT型に変えようとすると、これを実行します..

public class GenericCls<T> where T : struct, IComparable<T>, IEquatable<T>
{
    public static T AddValues(params T[] values)
    {
        T sum = default(T);
        if (values != null)
        {
            for (T i = default(T); i < values.Length; i++)
            {
                sum += values[i];
            }
        }
        return sum;
    }
}

まだエラーが発生します

Operator '<' cannot be applied to operands of type 'T' and 'int'
Operator '++' cannot be applied to operand of type 'T'
Cannot implicitly convert type 'T' to 'int'

何があっても、私はそれを機能させることができません。VS2010 (C# 4.0、.NET 4.0) を使用しています。C# 5.0 が最終的に VS2012 でリリースされる時期を知りたいです (私が知る限り、まだベータ段階ですよね?) これらの問題は処理されますか? それとも、ジェネリックの使用に関して非常に多くの制限が残っているのでしょうか?

4

3 に答える 3

2

言語を改善しなくても可能ですが、いくつかのトリックを使用する必要があり、既存の数値型には適用できず、新しい数値型を作成する必要があります。それらの 1 つは、奇妙に繰り返されるパターンclass C<T> : where T : C<T>です。もう 1 つのトリックは、操作に静的デリゲートを使用することです。数値クラスを次のように定義します (簡単にするために、加算のみを定義します)。

public abstract class Numeric<T>
    where T : Numeric<T>
{
    public static Func<T, T, T> Add;

    public static T operator +(Numeric<T> x, Numeric<T> y)
    {
        if (x == null) {
            return (T)y;
        }
        if (y == null) {
            return (T)x;
        }
        return Add((T)x, (T)y);
    }
}

演算子をオーバーロードする場合と同様に、少なくとも 1 つの型を指定する必要があることに注意してくださいNumeric<T>(1 つの型は、常に演算子をオーバーロードするクラスでなければなりません)。また、一般的な制約のためにNumeric<T>キャストできることにも注意してくださいTwhere T : Numeric<T>

これで、電卓を次のように宣言できます。演算子をNumeric<T>オーバーロードするため、ここで使用できます。++=

public class Calculator<T> where T : Numeric<T>
{
    public static T AddValues(params T[] values)
    {
        T sum = default(T);
        if (values != null) {
            for (int i = 0; i < values.Length; i++) {
                sum += values[i];
            }
        }
        return sum;
    }
}

具体的な Numeric クラスを定義しましょう。Add静的コンストラクターでは、静的デリゲートを定義します。オペレーターは静的であるため、このデリゲートもオペレーター メソッド内から呼び出されるため静的である必要があり、静的メンバーは仮想化できないため、このデリゲート トリックを使用する必要があります。

public class Complex : Numeric<Complex>
{
    static Complex()
    {
        Add = (x, y) => new Complex(x.Re + y.Re, x.Im + y.Im);
    }

    public double Re { get; private set; }
    public double Im { get; private set; }

    public Complex(double re, double im)
    {
        Re = re;
        Im = im;
    }

    public override string ToString()
    {
        return String.Format("({0}, {1})", Re, Im);
    }
}

このトリッキーな構造をテストしてみましょう

static class Test
{
    public static void AddComplexNumbers()
    {
        // Using the calculator
        var numbers = new Complex[] { new Complex(2, 7), new Complex(6, -2) };
        var result = Calculator<Complex>.AddValues(numbers);
        Console.WriteLine(result); // ==> (8, 5)

        // Directly
        var c1 = new Complex(2, 7);
        var c2 = new Complex(6, -2);
        result = c1 + c2;
        Console.WriteLine(result); // ==> (8, 5)

    }
}
于 2012-07-28T14:34:06.747 に答える
1

いいえ、この問題は改善されません。C#5 は、async-await といくつかのマイナーな機能を提供します。ただし、メソッド/演算子のオーバーロードで機能するジェネリックの拡張バージョンではありません。

比較には回避策としてIComparer<T>andを使用できますIComparable<T>が、算術演算には適切な解決策はありません。いくつかのテクニックがありますが、API を醜くしたり遅くしたりします。


微妙にValueType制約を適用しようとすると、「制約を特別なクラスにすることはできません」と表示されSystem.ValueTypeます

この制約に相当するのはstructキーワード iewhere T: structです。しかし、値型に制限しても、ここでは何も得られません。そして、それはなぜですか?算術をサポートしない値型と、サポートする参照型があります。したがって、値型であることは、必要なものと直交しています。

于 2012-07-28T13:11:57.840 に答える
0

残念ながら、現在 RC 状態にある C# 5.0 では何も変わりません。主に非同期プログラミングに焦点を当てました。

于 2012-07-28T13:12:14.447 に答える