C# 为什么我会在短、长而不是int的通用方法中遇到异常
我有这些方法来寻找最伟大的共同创造者C# 为什么我会在短、长而不是int的通用方法中遇到异常,c#,generics,C#,Generics,我有这些方法来寻找最伟大的共同创造者 private static T GenGCD(动态a、动态b) { //绝对值用于说明:a 0, (0,)=>数学Abs(b), (u,0)=>Math.Abs(a), _=>GCD(b,a%b) }; } 公共静态短GCD(这个短a,短b){返回GenGCD(a,b);} 公共静态intgcd(这个inta,intb){返回GenGCD(a,b);} 公共静态长GCD(这个长a,长b){返回GenGCD(a,b);} 像 短a=270; 短b=192;
private static T GenGCD(动态a、动态b)
{
//绝对值用于说明:a<0和/或b<0;b>a
返回(a,b)开关
{
(0, 0) => 0,
(0,)=>数学Abs(b),
(u,0)=>Math.Abs(a),
_=>GCD(b,a%b)
};
}
公共静态短GCD(这个短a,短b){返回GenGCD(a,b);}
公共静态intgcd(这个inta,intb){返回GenGCD(a,b);}
公共静态长GCD(这个长a,长b){返回GenGCD(a,b);}
像
短a=270;
短b=192;
短r=a.GCD(b)
或
inta=270;
int b=192;
int r=a.GCD(b)
或
长a=270;
长b=192;
长r=a.GCD(b)
当a
和b
是int
时,它工作,但当它们是long
时,我得到一个异常
未处理的异常。System.DivideByZeroException:尝试除以零。
目标(闭包、调用站点、对象、对象)
在MathExtensions.GenGCD[T](对象a、对象b)
在MathExtensions.GCD(int64a,int64b)
目标(闭包、调用站点、类型、对象、对象)
在System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](调用站点,T0 arg0,T1 arg1,T2 arg2)
在MathExtensions.GenGCD[T](对象a、对象b)
在MathExtensions.GCD(int64a,int64b)
在Program.Main()中
当它们short
时,我会得到一个不同的异常
未处理的异常。Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:无法将类型“int”隐式转换为“short”。存在显式转换(是否缺少强制转换?)
目标(闭包、调用站点、对象)
在System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](调用站点,T0 arg0)
在MathExtensions.GenGCD[T](对象a、对象b)
在MathExtensions.GCD(int16a,int16b)
在Program.Main()中
为什么它适用于int
,但不适用于long
或short
为什么它适用于int而不是long或short
因为0
特别是一个int
,因此如果dynamic
是,则0L
将不匹配它。您可以检查IL,如果0
打开动态
,它会专门检查值是否为int 0,而不是任何旧的0
我建议你做一些如下的事情。主要的变化是:
开关
(这避免了主要问题-由于类型不对齐,开关
不能按您希望的方式工作)GCD
)另外,如其他人建议的,考虑避免<代码>动态< /代码> -并且为每个类型实现单独的方法(例如一个用于代码> int <代码>,另一个用于<代码>长)。
使用系统;
公共静态类程序
{
私有静态T GenGCD(动态a,动态b),其中T:struct
{
如果(a==0){
如果(b==0){
返回(T)(对象)0;
}
返回Math.Abs(b);
}
else如果(b==0)
{
返回Math.Abs(a);
}
返回GenGCD((T)b,(T)(a%b));
}
公共静态短GCD(这个短a,短b){返回GenGCD(a,b);}
公共静态intgcd(这个inta,intb){返回GenGCD(a,b);}
公共静态长GCD(这个长a,长b){返回GenGCD(a,b);}
公共静态单GCD(这个单a,单b){返回GenGCD(a,b);}
公共静态void Main()
{
单个a=99;
单个b=87;
单个r=a.GCD(b);
控制台写入线(r);
}
}
为什么要使用动态
作为输入类型,而不是T
?(泛型的要点是什么?)您肯定不应该使用dynamic
作为编写适用于三种特定已知类型之一的代码的方法。只需编写三个重载,每种类型一个。您的代码将更容易理解,静态类型化,性能更好,而这一切都不糟糕。@Franz Gleichmann动态的是因为你不能在t
上使用数学运算符,math
不接受t
@Servy我只放了这三种类型,因为这是我决定测试代码的地方。我希望它适用于所有c#的整数类型。@Servy我这样做是因为我不希望每个整数类型都有一堆重复的代码。对于long
只使用一个方法可能就足够99%的情况了(可能有两种情况下,性能非常重要,Int32
和Int64
之间的差异非常明显)…如果关键的话,您仍然可以使用包装器将结果long
转换为较短的类型…@AlexeiLevenkov Yep,假设您不需要浮点/十进制。当然,我也不知道任何浮点类型对GCD有何用处…因为它们不能表示大多数有理数(即1/3)无论如何,它将被限制在整个部分……而对于那个大整数来说,会安全得多。@AlexeiLevenkov可以说是正确的,是的。但鉴于etc确实存在,显然有些人会使用它们。:)
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);
}
}