在不知道.NET类型的情况下添加两个数字?

时间:2009-08-01 14:05:06

标签: .net

当我不知道他们在.NET中的类型时,如何将两个数字加在一起?例如,您将如何实现以下功能?

public object AddTwoNumbers(object left, object right)
{
    /* What goes here? */
}

假设'left'和'right'参数是(盒装)值类型,如Int32,double,Decimal等。你不知道具体的类型,你只知道它是数字的,并且添加有意义为了它。

谢谢!

6 个答案:

答案 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;
}

如果您愿意接受leftright必须属于同一类型的限制,那就不错了:

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将在堆上构建一个新对象 您可以做一些可怕的事情,例如检查leftright的类型,但如果leftright的类型不同,会发生什么?在那种情况下哪种类型优先?即leftInt32rightfloat

答案 3 :(得分:2)

如果您不知道它们的表示方式,则无法添加值。 float和int使用相同数量的内存(32位)但具有完全不同的二进制表示(即,如果将其解释为int或float,则相同的二进制模式具有完全不同的值)。

您需要做的是将值转换为您可以添加的几种常见基本类型 - 例如,double和long。这对于任何较低或相等精度的值都可以正常工作,但仍然不允许您安全/准确地表示较大的值(例如,您仍然无法正确处理小数或int128)

.net 4.0中的动态类型允许您轻松完成此操作,但“在引擎盖下”它仍然在做同样的事情 - 将类型转换为它可以处理的类型。

答案 4 :(得分:1)

最安全的方式(可能不是最漂亮的)是使用反射并将它们分配给适当的类型变量并执行添加操作。

答案 5 :(得分:0)

您还可以使用F#使用的泛型类型“dispatch”方法。

实现它的代码非常冗长,但至少你得到了

  • 类型安全
  • 没有不必要的拳击
  • 隐式转换支持

这种方法与Jon在上面的做法类似。

相关问题