在动态中是否存在valuetype运算符处理的错误?

Mic*_*l B 1 c# dynamic

动态应该能够处理数学而不必让我考虑它,但即使在琐碎的情况下我也遇到了一些问题.考虑这个非常简单的功能::

 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.我说只是写了六次,而不是通过滥用泛型和动态来节省少量击键.