当我不知道他们在.NET中的类型时,如何将两个数字加在一起?例如,您将如何实现以下功能?
public object AddTwoNumbers(object left, object right)
{
/* What goes here? */
}
假设'left'和'right'参数是(盒装)值类型,如Int32,double,Decimal等。你不知道具体的类型,你只知道它是数字的,并且添加有意义为了它。
谢谢!
答案 0 :(得分:14)
在.NET 3.5及更早版本中,最简单的方法可能是测试每种类型 - 或者更确切地说,每种类型的组合 - 您可以处理,适当地转换并执行相关操作。你可以尝试使用反射来获取适当的运算符,但这可能会有一些奇怪的极端情况。
在.NET 4.0和C#4中,这很简单:
public object AddTwoNumbers(object left, object right)
{
dynamic x = left;
dynamic y = right;
return x + y;
}
如果您愿意接受left
和right
必须属于同一类型的限制,那就不错了:
using System;
using System.Collections.Generic;
public class Test
{
static Dictionary<Type, Func<object, object, object>> Adders =
new Dictionary<Type, Func<object, object, object>>
{
{ typeof(int), (x, y) => (int) x + (int) y },
{ typeof(double), (x, y) => (double) x + (double) y },
{ typeof(decimal), (x, y) => (decimal) x + (decimal) y },
{ typeof(long), (x, y) => (long) x + (long) y },
// etc
};
static object Add(object left, object right)
{
if (left.GetType() != right.GetType())
{
throw new ArgumentException("Types must be the same");
}
Func<object, object, object> adder;
if (!Adders.TryGetValue(left.GetType(), out adder))
{
throw new ArgumentException
("I don't have an adder for that type");
}
return adder(left, right);
}
static void Main()
{
Console.WriteLine(Add(3, 4));
Console.WriteLine(Add(3.5m, 4.2m));
Console.WriteLine(Add(3.5, 4.8));
}
}
答案 1 :(得分:4)
即使您确定可以添加它们,也无法添加任何您不知道其类型的内容。您必须将它们转换为特定类型。为了避免溢出,您可以将它们都转换为Double
,因为它可以处理其他类型的范围:
public object AddTwoNumbers(object left, object right) {
return Convert.ToDouble(left) + Convert.ToDouble(right);
}
但是,这并不能保证数字的精确性。
您可以创建重载方法来处理不同类型:
public int AddTwoNumbers(int left, int right) {
return left + right;
}
public double AddTwoNumbers(double left, double right) {
return left + right;
}
当然要求类型在编译时是已知的,并且不会在+运算符上添加任何内容。
如果这些都没有你想做的,我想你必须编写很多if
语句来检查参数的类型以进行正确的转换:
public object AddTwoNumbers(object left, object right) {
if (left is int && right is int) {
return (int)left + (int)right;
} else if (left is double && right is duble) {
return (double)left + (double)right;
} else ...
...
} else {
throw new ArgumentException("Arguments could not be added.");
}
}
答案 2 :(得分:2)
我不知道你想要达到的具体细节,但我强烈建议不要拳击
值类型它实际上不是一种有效的方法,因为CLR将在堆上构建一个新对象
您可以做一些可怕的事情,例如检查left
和right
的类型,但如果left
与right
的类型不同,会发生什么?在那种情况下哪种类型优先?即left
是Int32
而right
是float
?
答案 3 :(得分:2)
如果您不知道它们的表示方式,则无法添加值。 float和int使用相同数量的内存(32位)但具有完全不同的二进制表示(即,如果将其解释为int或float,则相同的二进制模式具有完全不同的值)。
您需要做的是将值转换为您可以添加的几种常见基本类型 - 例如,double和long。这对于任何较低或相等精度的值都可以正常工作,但仍然不允许您安全/准确地表示较大的值(例如,您仍然无法正确处理小数或int128)
.net 4.0中的动态类型允许您轻松完成此操作,但“在引擎盖下”它仍然在做同样的事情 - 将类型转换为它可以处理的类型。
答案 4 :(得分:1)
最安全的方式(可能不是最漂亮的)是使用反射并将它们分配给适当的类型变量并执行添加操作。
答案 5 :(得分:0)
您还可以使用F#使用的泛型类型“dispatch”方法。
实现它的代码非常冗长,但至少你得到了
这种方法与Jon在上面的做法类似。