我有这些方法来寻找最大公约数
private static T GenGCD<T> (dynamic a, dynamic b)
{
// Absolute values are use to account for: a < 0 and/or b < 0; b > a
return (a, b) switch
{
(0, 0) => 0,
(0, _) => Math.Abs(b),
(_, 0) => Math.Abs(a),
_ => GCD(b, a % b)
};
}
public static short GCD(this short a, short b) { return GenGCD<short>(a, b); }
public static int GCD(this int a, int b) { return GenGCD<int>(a, b); }
public static long GCD(this long a, long b) { return GenGCD<long>(a, b); }
使用
short a = 270;
short b = 192;
short r = a.GCD(b)
或
int a= 270;
int b = 192;
int r = a.GCD(b)
或
long a = 270;
long b = 192;
long r = a.GCD(b)
当a
和b
为int
时有效,但当它们为long
时,我得到一个异常
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
at CallSite.Target(Closure , CallSite , Object , Object )
at MathExtensions.GenGCD[T](Object a, Object b)
at MathExtensions.GCD(Int64 a, Int64 b)
at CallSite.Target(Closure , CallSite , Type , Object , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
at MathExtensions.GenGCD[T](Object a, Object b)
at MathExtensions.GCD(Int64 a, Int64 b)
at Program.Main()
,当它们是short
时,我得到一个不同的异常
Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?)
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at MathExtensions.GenGCD[T](Object a, Object b)
at MathExtensions.GCD(Int16 a, Int16 b)
at Program.Main()
为什么int
可以工作,而long
和short
不行?
为什么它可以为int而不是长或短工作?
因为0
是一个特定的int
,所以如果涉及dynamic
,0L
将不匹配它。您可以检查这里的IL,并看到如果0
被切换到dynamic
,它会特别检查值是int 0,而不是任何旧的0。
我的建议如下。关键的变化是:
- 不要使用
switch
(这避免了主要问题-switch
不像你想的那样,因为类型不对齐)。 - 改变递归,使方法调用自己(不通过
GCD
)。
另外,正如其他人建议的那样,考虑完全避免dynamic
-并为每种类型实现单独的方法(例如,一个用于int
,另一个用于long
)。
using System;
public static class Program
{
private static T GenGCD<T> (dynamic a, dynamic b) where T:struct
{
if (a == 0) {
if (b == 0) {
return (T)(object)0;
}
return Math.Abs(b);
}
else if (b == 0)
{
return Math.Abs(a);
}
return GenGCD<T>((T)b, (T)(a % b));
}
public static short GCD(this short a, short b) { return GenGCD<short>(a, b); }
public static int GCD(this int a, int b) { return GenGCD<int>(a, b); }
public static long GCD(this long a, long b) { return GenGCD<long>(a, b); }
public static Single GCD(this Single a, Single b) { return GenGCD<Single>(a, b); }
public static void Main()
{
Single a= 99;
Single b = 87;
Single r = a.GCD(b);
Console.WriteLine(r);
}
}