【问题标题】:What is the "base class" for C# numeric value types?C# 数值类型的“基类”是什么?
【发布时间】:2010-10-24 03:35:24
【问题描述】:

假设我想要一个接受任何类型数字的方法,是否有我可以使用的基类(或其他概念)?

据我所知,我必须为所有不同的数字类型(Int32、Int16、Byte、UInt32、Double、Float、Decimal 等)进行重载。这似乎非常乏味。要么使用“object”类型,要么使用类型“object”并在它们不可转换或分配给 double 时抛出异常——这非常糟糕,因为这意味着没有编译时检查。

更新: 好的,感谢 cmets,你是对的稻草人和马克,事实上,将其声明为 Double 实际上适用于除 Decimal 之外的所有对象。

所以我正在寻找的答案是 Double - 它在这里就像一个基类,因为大多数数字类型都可以分配给它。 (我猜 Decimal 不能分配给 Double,因为它可能会变得太大。)

public void TestFormatDollars() {
    int i = 5;
    string str = FormatDollars(i);   // this is OK
    byte b = 5;
    str = FormatDollars(b);     // this is OK
    decimal d = 5;
    str = FormatDollars(d);     // this does not compile - decimal is not assignable to double
}

public static string FormatDollars(double num) {
    return "$" + num;
}

【问题讨论】:

  • 哪些数字类型不能赋值给 double? (支持任意大数的大数类除外)
  • @scarecrow - 十进制是 96 位......很多其他的根本不适合范围/比例。
  • 也许你可以澄清一下你想对方法中的数字做什么?

标签: c# types


【解决方案1】:

答案是:您不需要为所有数字类型提供重载,只需为 DoubleDecimal 提供重载。所有其他(可能除了一些非常大的除外)将自动转换为这些。

不是基类,但实际上这是红鲱鱼。基类 System.ValueType 没有多大帮助,因为它包含非数字类型。我正在阅读的语言参考首先让我感到困惑:)

(我只是在寻找将答案归因于谁,它是稻草人和 Marc Gravell 的组合,但由于他们是 cmets,所以我将答案放在这里)

【讨论】:

  • 实际上,这给出了模棱两可的方法签名。重载其中一个就可以了。
【解决方案2】:

没有一个(或者至少没有一个只是意味着“数字”)。你可以使用:

void Foo<T>(T value) where T : struct {...}

但这允许 any 结构 - 不仅仅是数字。如果你想做算术,generic operators 可能有用。除此之外;重载它是最可行的选择。

【讨论】:

  • 链接已损坏。
【解决方案3】:

我做什么:

 public interface INumeric<T>
 {
     T Zero { get; }
     T One { get; }
     T MaxValue { get; }
     T MinValue { get; }
     T Add(T a, T b);
     // T Substract(....
     // T Mult...
 }  

 public struct Numeric: 
     INumeric<int>, 
     INumeric<float>,
     INumeric<byte>,
     INumeric<decimal>,
     // INumeric<other types>
 {
     int INumeric<int>.Zero => 0;
     int INumeric<int>.One => 1;
     int INumeric<int>.MinValue => int.MinValue;
     int INumeric<int>.MaxValue => int.MaxValue;
     int INumeric<int>.Add(int x, int y) => x + y;

     // other implementations...
 }

现在,您可以在方法中使用它:

bool IsZero<TNum, T>(TNum ops, T number) 
   where TNum : INumeric<T>
{
   return number == ops.Zero;      
}

或扩展方法

 public static bool IsZero<TNum, T>(this TNum ops, T number)
      where TNum : INumeric<T>
 {
      return number == ops.Zero;
 }

在你的代码中:

 ...
 var n = new Numeric(); // can be an static prop

 Console.WriteLine(IsZero(n, 5)); // false
 Console.WriteLine(IsZero(n, 0f)); // true
 Console.WriteLine(IsZero(n, "0")); // compiler error

或者,使用扩展方法:

 Console.WriteLine(n.IsZero(5));  // false
 Console.WriteLine(n.IsZero(0f)); // true
 Console.WriteLine(n.IsZero("0")); // compiler error

【讨论】:

    【解决方案4】:

    简短的回答是:数值类型是值类型,因此它们派生自 System.ValueType。 完整的答案是:你应该阅读这个article from MSDN。此外,我认为您应该阅读 C# 语言参考 :)。值类型不等于数值类型,因为值类型还包括结构和枚举。

    【讨论】:

    • MSDN 的文章并没有真正考虑当您想要一个参数来捕获各种数字而不是其他任何东西时使用什么是最佳类型 - 这就是我的要求。
    • 是的,但是文章显示十进制类型和其他浮点类型是不同的类型。
    【解决方案5】:

    数字类型的基类是ValueType

    不幸的是,这仍然无法帮助您:DateTimeboolEnum 和数百种其他类型也派生自 ValueType。 .NET 中没有 NumericType 基类。

    【讨论】:

    • 值类型不一定是数字,不是吗?
    • ValueType 还包括字符串和其他非数字值类型。
    • @Noldorin,你说得对,ValueType 包括数百种非数字类型,但字符串不是其中之一。 String 是一种引用类型(它的行为有点像值类型)。
    • 另外我不能使用 ValueType 作为参数声明然后用数字调用它,它说它找不到最佳匹配重载。
    • @mike,我不确定你的意思 - 我可以声明一个方法“public void Foo(ValueType val)”并将数字传递给它,尽管我真的不能做任何有用的事情它们在方法中。
    【解决方案6】:

    重载的方法签名在这里没有问题吗? 如果您希望一组受约束的方法执行相同的任务,您可以加载公共方法并调用一个私有方法,该方法通过将输入转换为双精度来获取任何数字。

    【讨论】:

    • 正式地说,这将是转换而不是演员表。
    • 这不是不可能的,只是烦人!因为有很多数字类型。这似乎是最好的解决方案,但我想知道是否有更好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 2013-05-27
    • 2011-07-01
    相关资源
    最近更新 更多