对C#中任意对象的数学运算

时间:2010-07-28 17:50:55

标签: c# object

我正在用C#实现玩具语言的翻译,为了用这种语言做数学,我想实现这样的函数:

public static object Add( object a, object b )
{
  // return the sum of a and b
  // each might be int, double, or one of many other numeric types
}

我可以想象这个函数的一个非常愚蠢和糟糕的实现,有大量的分支基于a和b的类型(使用is运算符)和一堆强制转换,但我的直觉是有更好的方法。

您认为这个功能的良好实现是什么?

5 个答案:

答案 0 :(得分:19)

如果:

  • 您只想要一个易于编程的解决方案
  • 您的小语言与C#
  • 具有相同的算术规则
  • 您可以使用C#4
  • 你并不特别关心表现

然后你可以这样做:

public static object Add(dynamic left, dynamic right)
{
    return left + right;
}

完成。会发生什么情况,当调用此方法时,代码将再次启动C#编译器并询问编译器“如果必须添加这两项内容,您会怎么做,但是您知道它们的运行时类型是什么编译时间?“ (动态语言运行时将缓存结果,以便下次有人尝试添加两个整数时,编译器不会再次启动,它们只是重新使用编译器传回DLR的lambda。)

如果您想实施自己的添加规则,欢迎来到我的世界。没有神奇的道路可以避免大量的类型检查和切换。对于添加两种任意类型,可能存在数百种的可能情况,您必须全部检查它们。

我们在C#中处理这种复杂性的方式是在较小的类型子集上定义加法运算符:int,uint,long,ulong,decimal,double,float,all enums,all delegates,string和所有可空的版本那些价值类型。 (然后将枚举视为其基础类型,这进一步简化了事情。)

因此,例如当你将一个ushort添加到short时我们通过说ushort和short都是int的特殊情况来简化问题,然后解决添加两个int的问题。这大大减少了我们必须编写的代码量。但请相信我,C#中的二元运算符重载决策算法是成千上万行代码。这不是一个容易的问题。

如果你的玩具语言是一个有自己规则的动态语言,那么你可以考虑实现IDynamicMetaObjectProvider并使用DLR机制来实现算术和其他操作,如函数调用。

答案 1 :(得分:6)

将您的值转换为最宽的类型,例如,转换为十进制。所有类型如int,double,short等都实现了IConvertible接口(http://msdn.microsoft.com/en-us/library/system.iconvertible_members.aspx)。它公开了ToDecimal方法,该方法可用于将值转换为Decimal类型。转换类也非常有用

decimal aop = Convert.ToDecimal(a);
decimal bop = Convert.ToDecimal(b);
decimal sum = aop + bop;
return Convert.ChangeType(sum, typeof(a)); // Changing type from decimal to type of the first operand.

答案 2 :(得分:1)

您可以做的一件事就是为玩具语言编写自己的对象库。它可以是真实类或接口。这样,您可以确保所有类都具有适用于所有操作的某种功能(即使它只是为了抛出运行时NotSupported异常)。你可以使用接口或抽象函数来实现真正常见的东西(比如ToString或Equals),或者使用消息传递或其他方法进行不常见的操作。

(p.s。我与STO交叉发布,但我喜欢STO对数字类型的想法。)

答案 3 :(得分:1)

立即采取最简单的方法就是按照你所说的方式测试类型。

但是因为这是一个玩具语言实现(对你有好处!)然后我会建议使用比object更好的抽象来传递解释器中的值。也许创建一个LanguageNameObject基类,然后你可以添加你想要帮助你实现这个方法的所有帮助方法。基本上Object类对你来说是一个糟糕的抽象......所以建立一个更好的抽象!

答案 4 :(得分:0)

有趣的是,我会在进入的对象上使用typeof()运算符,并针对您将允许执行的类型测试这些操作。我还想象如果奇怪的类型试图加在一起,你会抛出异常吗?

理想情况下,如果你只允许添加int,float,double等,我真的只需要创建Add方法的重载版本来处理那些不同的情况。