1

我可以使用泛型创建一个采用整数类型的方法,并且仍然能够在这些类型的方法内进行基本的数学运算吗?

我的情况:我编写了一个方法,它接受一个 int 类型的值并返回该值是否为素数。后来我需要该方法来处理更大的数字,因此我将输入类型更改为 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)

等等等等……

4

3 回答 3

3

您可以在dynamic.NET 4.0 中使用关键字

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);
}
于 2013-09-16T01:29:56.183 回答
1

您可能不想使用以下任何一种:

  • dynamic
  • 表达式树
  • DynamicMethod

因为与整数算术相比,它们都非常慢(它们使用委托)。

最好的办法是在 MSIL 中使用 、 等算术函数进行程序集AddSubtract然后从 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
    }
}
于 2013-09-16T19:00:18.830 回答
0

我有另一个解决方案,它涉及调用动态方法并发出操作码。幸运的是,其他人在这个领域做了很多工作,我可以编译一个库来极大地简化事情。

Static<T>http://ideone.com/IfiSCo获取源代码,以便您进行如下调用:

/*
 * 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
    }
}
于 2013-09-16T18:56:25.660 回答