2

四次元ベクトルを表現する構造を作ろうとしています。

私はこのようなものを作りました:

struct Vector4D<T> 
{
    public T v1;
    public T v2;
    public T v3;
    public T v4;

    //...

    public static Vector4D<T> operator *(Vector4D<T> a, T b)
    {
        a.v1 *= b;
        a.v2 *= b;
        a.v3 *= b;
        a.v4 *= b;
        return a;
    }
}

T が Int32、Int64、Double、Single、Decimal などの数値型でない場合、この構造は意味がありません...

したがって、私の質問は、T を Int16、Int32、Int64、UInt16、UInt32、UInt64、Byte、SByte、Single、Double、Decimal のいずれかの型に制限するにはどうすればよいですか?

私はこのようなことをしようとしていました

struct Vector4D<T> where T : Int16, Int32, Int64 // and so go on
{
    //....
}

しかし、うまくいきませんでした。

4

2 に答える 2

1

タイプごとに乗算メソッドを明示的に記述する必要があります。

ただし、このコンパイル可能なコード サンプルが示すように、少し単純化できます。

using System;

namespace Demo
{
    internal class Program
    {
        static void Main()
        {
            var d = new Vector4D<double>{v1=1, v2=2, v3=3, v4=4};
            Console.WriteLine(d*2); // Prints 2, 4, 6, 8

            var i = new Vector4D<int>{v1=1, v2=2, v3=3, v4=4};
            Console.WriteLine(i*2); // Prints 2, 4, 6, 8

            // This will throw a "NotSupported" exception:
            var s = new Vector4D<string>{v1="1", v2="2", v3="3", v4="4"};
            Console.WriteLine(s*"");
        }
    }

    partial struct Vector4D<T>
    {
        public T v1;
        public T v2;
        public T v3;
        public T v4;

        public static Vector4D<T> operator *(Vector4D<T> a, T b)
        {
            a.v1 = multiply(a.v1, b);
            a.v2 = multiply(a.v2, b);
            a.v3 = multiply(a.v3, b);
            a.v4 = multiply(a.v4, b);
            return a;
        }

        public override string ToString()
        {
            return string.Format("v1: {0}, v2: {1}, v3: {2}, v4: {3}", v1, v2, v3, v4);
        }

        private static Func<T, T, T> multiply;
    }

    // Partial just to keep this logic separate.

    partial struct Vector4D<T>
    {
        static Vector4D() // Called only once for each T.
        {
            if (typeof(T) == typeof(int))
                Vector4D<int>.multiply = (a, b) => a*b;
            else if (typeof(T) == typeof(double))
                Vector4D<double>.multiply = (a, b) => a*b;
            else if (typeof(T) == typeof(float))
                Vector4D<float>.multiply = (a, b) => a*b;
            else
                multiply = (a, b) =>
                {
                    string message = string.Format("Vector4D<{0}> not supported.", typeof(T));
                    throw new NotSupportedException(message);
                };
        }
    }
}

こうすることで、すべての乗算 (およびおそらく除算、加算、減算) ロジックを 2 番目の部分構造体に配置し、すべてをメイン ロジックから分離することができます。

2 番目の部分構造体には、構造体の作成に使用される型 T ごとに (アセンブリ ドメインごとに) 1 回だけ呼び出される静的型コンストラクターのみが含まれます。

型をクエリするオーバーヘッドはありますが、プログラムの実行ごとに 1 回だけであり、オーバーヘッドはかなり低いと思います。

また、部分構造体を使用する必要はまったくありません。静的型コンストラクターを構造体実装の残りの部分に配置するだけです。構造体の残りのロジックとは別に考えることができる純粋な初期化ロジックであるため、例としてのみ分離しました。

重要乗算演算を定義していない型で Vector4D を使用すると、 でNotSupportedException定義された が得られることに注意してくださいstatic Vector4D()。これは、少なくとも次の行に沿って、何が間違っているかを正確に伝えます。

Unhandled Exception: System.NotSupportedException: Vector4D<System.String> not supported.

于 2013-05-05T12:59:38.217 に答える
0

この方法ではなく、これを行うことはできません。

C# はジェネリック型について何も知りませんT。数字ですか?文字列ですか?あなたはそれで数学をすることができますか?

これを機能させたい場合は、一般的な電卓を使用する必要があります。自分で構築する必要があります。詳細については、http: //www.codeproject.com/Articles/8531/Using-generics-for-calculationsをご覧ください。

より簡単な解決策は次のとおりです。

a.v1 = Convert.ChangeType(Convert.ToDecimal(a.v1) * Convert.ToDecimal(b), typeof(T));

編集

別の場所にいくつかのライブラリ関数を作成しました。これを使用して、独自のコードに実装できます。これらの数値で計算するのは簡単です。あなたの Vector クラスは次のようになります。

partial struct Vector4D<T>
where T: IComparable<T>, IEquatable<T>
{
    public Number<T> v1;
    public Number<T> v2;
    public Number<T> v3;
    public Number<T> v4;

    public static Vector4D<T> operator *(Vector4D<T> a, T b)
    {
        a.v1 *= b;
        a.v2 *= b;
        a.v3 *= b;
        a.v4 *= b;
        return a;
    }
}

参照: https://codereview.stackexchange.com/questions/26022/improvement-requested-for-generic-calculator-and-generic-number

于 2013-05-05T11:53:45.447 に答える