我正在用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
}
Run Code Online (Sandbox Code Playgroud)
我可以想象一个非常愚蠢和糟糕的实现这个函数的大量分支基于a和b的类型(使用is运算符)和一堆强制转换,但我的直觉是有更好的方法.
您认为这个功能的良好实现是什么?
Eri*_*ert 19
如果:
然后你可以这样做:
public static object Add(dynamic left, dynamic right)
{
return left + right;
}
Run Code Online (Sandbox Code Playgroud)
完成.会发生什么情况,当调用此方法时,代码将再次启动C#编译器并询问编译器"如果必须添加这两项内容,您会怎么做,但是您在编译时知道它们的运行时类型?" (然后动态语言运行时将缓存结果,以便下次有人尝试添加两个整数时,编译器不会再次启动,它们只是重新使用编译器返回给DLR的lambda.)
如果您想实施自己的添加规则,欢迎来到我的世界.没有神奇的道路可以避免大量的类型检查和切换.实际上有数百种可能的情况需要添加两种任意类型,您必须全部检查它们.
我们在C#中处理这种复杂性的方式是在较小的类型子集上定义加法运算符:int,uint,long,ulong,decimal,double,float,所有枚举,所有委托,字符串以及这些值的所有可空版本类型.(然后将枚举视为其基础类型,这进一步简化了事情.)
因此,例如当你将一个ushort添加到short时我们通过说ushort和short都是int的特殊情况来简化问题,然后解决添加两个int的问题.这大大减少了我们必须编写的代码量.但请相信我,C#中的二元运算符重载决策算法是成千上万行代码.这不是一个容易的问题.
如果您的玩具语言是一个具有自己规则的动态语言,那么您可以考虑实现IDynamicMetaObjectProvider并使用DLR机制来实现算术和其他操作,如函数调用.
将值转换为最宽类型,例如,转换为十进制.所有类型如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.
Run Code Online (Sandbox Code Playgroud)