[英]How to use C# Generics to limit method to integer types and still use operators
我可以使用泛型來創建一個采用整數類型的方法,並且仍然能夠在這些類型的方法內部進行基本的數學運算嗎?
我的情況:我編寫了一個方法,它接受int類型的值並返回值是否為prime。 我后來需要這個方法來處理更大的數字,所以我將輸入類型更改為Int64,但這對速度有負面影響。 效率在這里非常重要。
我對泛型一無所知,但認為它會阻止我有兩個幾乎相同的重載方法。 然而,我無法讓它工作,我不知道是不是因為我試圖錯誤地使用泛型,或者我有語法錯誤。
我認為將類型限制為“int”和“UInt64”將允許我在方法中使用數學運算符,例如'>'和'%',但這似乎不起作用。
代碼:
/// <summary>
/// Tests whether a number is prime.
/// </summary>
public static bool IsPrime<T>(T numToTest) where T: int, UInt64
{
List<T> primeList = new List<T>();
primeList.Add(2); // Give the list an initial prime number. error here when using generics.
return IsPrime(numToTest, primeList);
}
/// <summary>
/// Tests whether a number is prime. Takes an initial list of primes as input to speed the method up.
/// </summary>
public static bool IsPrime<T>(T numToTest, List<T> primeList)
{
bool isPrime = true;
T limit = (T)Math.Sqrt(numToTest); //error here when using generics.
primeList = Prime.AllPrimesUnder(limit, primeList); // If we don't have enough primes to properly test the number, get more.
foreach (T prime in primeList)
{
if (prime > limit) //error here when using generics.
break;
if (numToTest % prime == 0) //error here when using generics.
{
isPrime = false;
break;
}
}
return isPrime;
}
我所知道的唯一選擇是:
public static bool IsPrime<int>(int numToTest, List<int> primeList)
public static bool IsPrime<UInt64>(UInt64 numToTest, List<UInt64> primeList)
public static bool IsPrime<BigInteger>(BigInteger numToTest, List<BigInteger> primeList)
等等......
您可以在.NET 4.0中使用dynamic
關鍵字
public static T Add<T>(T x, T y)
{
return (T)((dynamic)x+(dynamic)y);
}
static void Main(string[] args)
{
int a=Add(10, 11);
long b=Add(34L, 23L);
uint c=Add(4u, 15u);
}
甚至是自定義類型
public struct MyInt
{
public static MyInt operator+(MyInt a, MyInt b)
{
}
}
{
MyInt d=new MyInt(...);
MyInt e=new MyInt(...);
MyInt f=Add(d, e);
}
您可能不想使用以下任何一種:
dynamic
DynamicMethod
因為與整數算術相比,它們都非常慢(它們使用委托)。
最好的辦法是在MSIL中使用Add
, Subtract
等算術函數進行匯編,然后從C#代碼中調用它們。
// Compile with:
// C:\Windows\Microsoft.NET\Framework\v2.0.50727\ilasm.exe Arithmetic.il /dll
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 2:0:0:0
}
.assembly Arithmetic
{
}
.module Arithmetic.dll
.subsystem 0x0003
.class public abstract auto ansi sealed beforefieldinit Helper.Arithmetic
extends [mscorlib]System.Object
{
.method public hidebysig static !!T Or<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
or
ret
}
.method public hidebysig static !!T And<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
and
ret
}
.method public hidebysig static !!T Xor<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
xor
ret
}
.method public hidebysig static !!T Not<T>(!!T val) cil managed
{
.maxstack 1
ldarg.0
not
ret
}
.method public hidebysig static !!T Add<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
add
ret
}
.method public hidebysig static !!T AddOverflow<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
add.ovf
ret
}
.method public hidebysig static !!T AddOverflowUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
add.ovf.un
ret
}
.method public hidebysig static !!T Subtract<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
sub
ret
}
.method public hidebysig static !!T SubtractOverflow<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
sub.ovf
ret
}
.method public hidebysig static !!T SubtractOverflowUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
sub.ovf.un
ret
}
.method public hidebysig static !!T Multiply<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
mul
ret
}
.method public hidebysig static !!T MultiplyOverflow<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
mul.ovf
ret
}
.method public hidebysig static !!T MultiplyOverflowUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
mul.ovf.un
ret
}
.method public hidebysig static !!T Divide<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
div
ret
}
.method public hidebysig static !!T DivideUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
div.un
ret
}
.method public hidebysig static !!T Remainder<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
rem
ret
}
.method public hidebysig static !!T RemainderUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
rem.un
ret
}
.method public hidebysig static bool Equals<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
ceq
ret
}
.method public hidebysig static bool IsLessThan<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
clt
ret
}
.method public hidebysig static bool IsLessThanUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
clt.un
ret
}
.method public hidebysig static bool IsLessThanOrEqualTo<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
cgt
ldc.i4.0
ceq
ret
}
.method public hidebysig static bool IsLessThanOrEqualToUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
cgt.un
ldc.i4.0
ceq
ret
}
.method public hidebysig static bool IsGreaterThan<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
cgt
ret
}
.method public hidebysig static bool IsGreaterThanUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
cgt.un
ret
}
.method public hidebysig static bool IsGreaterThanOrEqualTo<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
clt
ldc.i4.0
ceq
ret
}
.method public hidebysig static bool IsGreaterThanOrEqualToUnsigned<T>(!!T a, !!T b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
clt.un
ldc.i4.0
ceq
ret
}
.method public hidebysig static !!T ShiftLeft<T>(!!T a, int32 b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shl
ret
}
.method public hidebysig static !!T ShiftLeft<T>(!!T a, uint32 b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shl
ret
}
.method public hidebysig static !!T ShiftLeft<T>(!!T a, native int b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shl
ret
}
.method public hidebysig static !!T ShiftLeft<T>(!!T a, native uint b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shl
ret
}
.method public hidebysig static !!T ShiftRight<T>(!!T a, int32 b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr
ret
}
.method public hidebysig static !!T ShiftRight<T>(!!T a, uint32 b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr
ret
}
.method public hidebysig static !!T ShiftRight<T>(!!T a, native int b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr
ret
}
.method public hidebysig static !!T ShiftRight<T>(!!T a, native uint b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr
ret
}
.method public hidebysig static !!T ShiftRightUnsigned<T>(!!T a, int32 b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr.un
ret
}
.method public hidebysig static !!T ShiftRightUnsigned<T>(!!T a, uint32 b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr.un
ret
}
.method public hidebysig static !!T ShiftRightUnsigned<T>(!!T a, native int b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr.un
ret
}
.method public hidebysig static !!T ShiftRightUnsigned<T>(!!T a, native uint b) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
shr.un
ret
}
.method public hidebysig static native uint DivideCeiling(native uint a, native uint b) cil managed
{
.maxstack 4
ldarg.0
ldarg.1
ldc.i4.1
conv.u
sub.ovf.un
add.ovf.un
ldarg.1
div.un
ret
}
.method public hidebysig static uint32 DivideCeiling(uint32 a, uint32 b) cil managed
{
.maxstack 4
ldarg.0
ldarg.1
ldc.i4.1
sub.ovf.un
add.ovf.un
ldarg.1
div.un
ret
}
.method public hidebysig static uint64 DivideCeiling(uint64 a, uint64 b) cil managed
{
.maxstack 4
ldarg.0
ldarg.1
ldc.i8 0x1
sub.ovf.un
add.ovf.un
ldarg.1
div.un
ret
}
.method public hidebysig static native int DivideCeiling(native int a, native int b) cil managed
{
.maxstack 4
ldarg.0
ldarg.1
ldc.i4.1
conv.i
sub.ovf.un
add.ovf.un
ldarg.1
div.un
ret
}
.method public hidebysig static int32 DivideCeiling(int32 a, int32 b) cil managed
{
.maxstack 4
ldarg.0
ldarg.1
ldc.i4.1
sub.ovf.un
add.ovf.un
ldarg.1
div.un
ret
}
.method public hidebysig static int64 DivideCeiling(int64 a, int64 b) cil managed
{
.maxstack 4
ldarg.0
ldarg.1
ldc.i8 0x1
sub.ovf.un
add.ovf.un
ldarg.1
div.un
ret
}
.method public hidebysig static !!T Lerp<T>(!!T min, !!T weight, !!T max) cil managed
{
.maxstack 3
ldarg.0
ldarg.1
ldarg.0
sub
ldarg.2
mul
add
ret
}
.method public hidebysig static !!T LerpOverflow<T>(!!T min, !!T weight, !!T max) cil managed
{
.maxstack 3
ldarg.0
ldarg.1
ldarg.0
sub.ovf
ldarg.2
mul.ovf
add.ovf
ret
}
.method public hidebysig static !!T LerpOverflowUnsigned<T>(!!T min, !!T weight, !!T max) cil managed
{
.maxstack 3
ldarg.0
ldarg.1
ldarg.0
sub.ovf.un
ldarg.2
mul.ovf.un
add.ovf.un
ret
}
.method public hidebysig static bool IsBetween<T>(!!T 'value', !!T min, !!T max) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
clt
ldarg.0
ldarg.2
cgt
or
ldc.i4.0
ceq
ret
}
.method public hidebysig static bool IsBetweenUnsigned<T>(!!T 'value', !!T min, !!T max) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
clt.un
ldarg.0
ldarg.2
cgt.un
or
ldc.i4.0
ceq
ret
}
.method public hidebysig static bool IsStrictlyBetween<T>(!!T 'value', !!T min, !!T max) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
cgt
ldarg.0
ldarg.2
clt
and
ret
}
.method public hidebysig static bool IsStrictlyBetweenUnsigned<T>(!!T 'value', !!T min, !!T max) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
cgt.un
ldarg.0
ldarg.2
clt.un
and
ret
}
}
我有另一個解決方案,involes調用動態方法和發出操作碼。 幸運的是,其他人已經在這個fiels上做了很多工作,我可以編譯一個能夠極大地簡化事情的庫。
請從http://ideone.com/IfiSCo獲取Static<T>
的源代碼,以便您撥打以下電話:
/*
* This file provides dynamic invocation of method, fields and properties
* based on IL code generation.
*
* This code was heavily influenced by
*
* a) Keith Farmer's Operator Overloading with Generics at
* http://www.codeproject.com/csharp/genericoperators.asp
*
* b) Douglas Gregor and Andrew Lumsdaine Operator<T> class for use in MPI
* environments, licensed under http://www.boost.org/LICENSE_1_0.txt
* http://www.osl.iu.edu/research/mpi.net/svn/
*
*/
public class Static<T>
{
// code emited for brevity
/// <summary>
/// Return the add operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Add { get { return Operator(BinaryOperator.op_Addition); } }
}
class Program
{
public struct MyStruct
{
public readonly int x;
public MyStruct(int x) { this.x=x; }
public static MyStruct operator+(MyStruct a, MyStruct b)
{
return new MyStruct(a.x+b.x);
}
}
static void Main(string[] args)
{
int a=Static<int>.Add(1, 2);
uint b=Static<uint>.Add(1u, 2u);
long c=Static<long>.Add(1U, 2U);
MyStruct d = new MyStruct(1);
MyStruct e = new MyStruct(2);
MyStruct f=Static<MyStruct>.Add(d, e);
// will result in f.x=3
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.