动态应该能够处理数学而不必让我考虑它,但即使在琐碎的情况下我也遇到了一些问题.考虑这个非常简单的功能::
public static T DynamicFactorial<T>(T input)
{
dynamic num = input;
dynamic res = 1;
for (; num > 1; res *= num, num -=1) ;
return res;
}
Run Code Online (Sandbox Code Playgroud)
这是一个应该处理任何数字类型并对其执行阶乘的函数.不幸的是,当我尝试计算时,这给了我以下异常DynamicFactorial(5UL):
Operator '*=' cannot be applied to operands of type 'int' and 'ulong'
请不要说我可以将此代码转换为递归调用,因为这是一个示例.我的问题是,如果你试图使用动态来使用一元赋值运算符,强迫我知道我在编译时计算的类型是没有意义的.一个"潜在的"解决方案是这样做::
public static T DynamicFactorial<T>(T input)
{
dynamic num = input;
T ONE = (T)(1 as dynamic);
dynamic res = ONE;
for (; num > ONE; res *= num, num -=ONE) ;
return res;
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,但神圣的地狱是这个丑陋的,并要求我创建一个我计划实际使用的类型的常量,这至少可以说是蹩脚的.
Eri*_*ert 16
"动态"的基本设计原则是,如果编译器已经被赋予运行时类型,则运行时的分析与编译时的分析完全相同.
那么让我们来看一下代码的修改版本:
ulong input = whatever;
dynamic num = input;
dynamic res = 1;
res = res * num;
Run Code Online (Sandbox Code Playgroud)
这应该在运行时的行为恰好如同编译器已经知道的一切类型标注为"动态"的.它的行为应该完全如此
ulong input = whatever;
object num = input;
object res = 1;
res = (int)res * (ulong)num;
Run Code Online (Sandbox Code Playgroud)
并且该程序在编译时出错,因此逻辑上动态版本必须在运行时给出相同的错误.
动态应该能够处理数学而不必让我考虑它
绝对不是.这不是动态特征的设计原则.动态特性的目的是简化C#代码与设计用于与动态语言交互的库中的代码的交互,无论是现代库(如为Python和Ruby设计的那些),还是遗留库(如通过VB6为COM自动化设计的库)或VBScript).在我们设计此功能时,我们完全没有对算术表达式的结果进行VB风格的类型提升,而且正如您所发现的那样,它的表现非常糟糕.
让我非常清楚:动态不是让C#成为一种动态语言,这似乎是你认为的.动态是让C#成为一种静态类型语言,可以与为动态语言设计的库很好地互操作.如果您想要的是具有动态算术的语言,请考虑使用Visual Basic或Python.
(顺便提一下,有些人可能想知道为什么int + ulong在C#中不合法.在C#中有七个非提升数字加法运算符:int + int,uint + uint,long + long,ulong + ulong,float + float,double + double和decimal + decimal在这七个中,哪个是最好的?int + int,uint + uint和long + long是因为ulong可能不合适.ulong + ulong因为int可能是负的而出局.这会留下float,double和decimal浮点数比双精度更好(因为它更具体)所以双重消失.但是将ulong转换为float也不比将ulong转换为十进制更好也不差.因为我们在这里有一个歧义,所以我们产生了一个错误.如果由于某些奇怪的原因你必须在ulong中添加一个int来解决歧义.)
最后,我注意到有办法做你想做的事.我还没有尝试过,但这可能有用:
public static T DynamicFactorial<T>(T input)
{
dynamic num = input;
dynamic one = default(T);
one++;
dynamic res = one;
while (num > one)
{
res *= num;
num--;
}
return res;
}
Run Code Online (Sandbox Code Playgroud)
这适用于默认值为零并且在其上定义了++, - 和*运算符的任何类型.
然而,这是严重的,缓慢的,滥用泛型.你真的想要计算ushort的阶乘吗?Factorial是一个很容易定义的函数,你可能不需要超过六个版本的tops.我说只是写了六次,而不是通过滥用泛型和动态来节省少量击键.