为什么我在短和长而不是int的通用方法中得到异常

  • 本文关键字:int 方法 异常 c# generics
  • 更新时间 :
  • 英文 :


我有这些方法来寻找最大公约数

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)

abint时有效,但当它们为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可以工作,而longshort不行?

为什么它可以为int而不是长或短工作?

因为0是一个特定的int,所以如果涉及dynamic,0L将不匹配它。您可以检查这里的IL,并看到如果0被切换到dynamic,它会特别检查值是int 0,而不是任何旧的0。

我的建议如下。关键的变化是:

  1. 不要使用switch(这避免了主要问题-switch不像你想的那样,因为类型不对齐)。
  2. 改变递归,使方法调用自己(不通过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);
}
}

最新更新