泛型结构-如何约束类型参数
本文关键字:约束 类型参数 何约束 结构 泛型 | 更新日期: 2023-09-27 18:12:16
我正在尝试制作代表四维向量的结构。
我做了这样的代码:
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
{
//....
}
但它没有工作。
您必须为每个类型显式地编写乘法方法。
但是,您可以将事情简化一点,如下面的可编译代码示例所示: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);
};
}
}
}
这样,就可以把所有的乘法(可能还有除法、加法和减法)逻辑放入第二个部分结构体中,并使其与主逻辑分开。
第二个部分结构只包含一个静态类型构造函数,对于用于创建结构的每种类型T,该构造函数只调用一次(每个汇编域)。
你确实有查询类型的开销,但它只在程序运行一次,我猜开销会很低。
同样,您根本不需要使用部分结构体—您可以将静态类型构造函数与结构体实现的其余部分放在一起。我只把它作为一个例子分离出来,因为它是纯粹的初始化逻辑,你可以把它和结构体的其他逻辑分开考虑。
重要的请注意,如果您使用Vector4D与您没有定义乘法操作的类型,您将获得static Vector4D()
中定义的NotSupportedException
。这至少可以告诉您哪里出了问题,如下所示:
Unhandled Exception: System.NotSupportedException: Vector4D<System.String> not supported.
你不能这样做,不能这样做。
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