【问题标题】:C# Comparing numbers generically [duplicate]C#一般比较数字[重复]
【发布时间】:2018-09-18 17:52:13
【问题描述】:

我正在编写一个函数,它采用任意原始类型的数量并决定该数量所支持的最小类型:

public static Type GetSmallestType( decimal value )
{
  return
    value.CompareTo( sbyte.MinValue ) >= 0 && value.CompareTo( sbyte.MaxValue ) <= 0 ? typeof( sbyte ) :
    value.CompareTo( byte.MinValue ) >= 0 && value.CompareTo( byte.MaxValue ) <= 0 ? typeof( byte ) :
    value.CompareTo( short.MinValue ) >= 0 && value.CompareTo( short.MaxValue ) <= 0 ? typeof( short ) :
    value.CompareTo( ushort.MinValue ) >= 0 && value.CompareTo( ushort.MaxValue ) <= 0 ? typeof( ushort ) :
    value.CompareTo( int.MinValue ) >= 0 && value.CompareTo( int.MaxValue ) <= 0 ? typeof( int ) :
    value.CompareTo( uint.MinValue ) >= 0 && value.CompareTo( uint.MaxValue ) <= 0 ? typeof( uint ) :
    value.CompareTo( long.MinValue ) >= 0 && value.CompareTo( long.MaxValue ) <= 0 ? typeof( long ) :
    value.CompareTo( ulong.MinValue ) >= 0 && value.CompareTo( ulong.MaxValue ) <= 0 ? typeof( ulong ) :
    typeof( decimal );
}

// e.g. GetSmallestType( -10 ) == typeof( sbyte )

此实现有效,但我想避免为每个单独的类型使用重载方法,因为它会导致大量重复代码。

当我尝试将其转换为接受泛型参数的泛型函数时,它会抛出一个错误,指出 Object must be of type Int32

public static Type GetSmallestType<T>( T value )
  where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{ ... }

目标是将值转换为最小的可用类型(由上述方法返回)并将其存储在通用树节点中。 然后这个问题就变成了能够比较所有原始类型的问题,无论是使用强制转换还是其他方法,因为许多原始类型不能直接比较。

这是一个(可能是不必要的)内存优化问题,我只是为了好玩。

【问题讨论】:

  • 小心混合浮点数和整数(整数)。
  • 问题是:知道类型能让你做什么?你能说出实际的问题吗?您可能正在尝试解决问题或在不需要的地方进行优化
  • 我认为这种方法永远不会返回 long/ulong,因为该范围内的任何值也适合 float 范围 - 就像@DennisKuypers 提到的那样,您可以存储一个 @ float 中的 987654327@ 值但会丢失精度。
  • @DennisKuypers 本质上,我试图取一个给定的原始值,并找到最小的类型,以便我最终可以将该值转换为该类型以提高内存效率。可能不是必要的优化,但我正在尝试一些挑战和乐趣。此外,这是在设计时考虑到整数。我理解浮点数会带来的问题,如果太麻烦就省略了。然而,这仍然存在比较其他原语的问题。
  • 问题是您将返回各种数字类型中的一种,并且您必须绕过静态类型 - 这很可能会超过您所做的“优化”。

标签: c#


【解决方案1】:

您可以将两者都转换为动态。是的,它排序违背了使用泛型方法的目的,但如果类型是数字,它就可以工作。 struct 约束将有助于防止类被传递。

看起来ulong 不适用于此方法,但其他所有方法都可以。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetSmallestType(100)); // System.SByte
        Console.WriteLine(GetSmallestType(200)); // System.Byte
        Console.WriteLine(GetSmallestType(30_000)); // System.Int16
        Console.WriteLine(GetSmallestType(60_000)); // System.UInt15
        Console.WriteLine(GetSmallestType(100_000)); // System.Int32
        Console.WriteLine(GetSmallestType(4_000_000_000)); // System.UInt23
        Console.WriteLine(GetSmallestType(100_000_000_000)); // System.Int64
        Console.WriteLine(GetSmallestType(20_000_000_000_000_000_000m)); // System.Decimal
    }

    public static Type GetSmallestType<T>(T propertyValue)
        where T : struct
    {
        dynamic value = propertyValue;

        return
            value >= (dynamic)sbyte.MinValue && value <= (dynamic)sbyte.MaxValue ? typeof(sbyte) :
            value >= (dynamic)byte.MinValue && value <= (dynamic)byte.MaxValue ? typeof(byte) :
            value >= (dynamic)short.MinValue && value <= (dynamic)short.MaxValue ? typeof(short) :
            value >= (dynamic)ushort.MinValue && value <= (dynamic)ushort.MaxValue ? typeof(ushort) :
            value >= (dynamic)int.MinValue && value <= (dynamic)int.MaxValue ? typeof(int) :
            value >= (dynamic)uint.MinValue && value <= (dynamic)uint.MaxValue ? typeof(uint) :
            value >= (dynamic)long.MinValue && value <= (dynamic)long.MaxValue ? typeof(long) :
            typeof(decimal);
    }
}

【讨论】:

  • 那么有一个通用参数有什么意义呢?
  • @DennisKuypers 您仍然可以确保类型是结构,因此不能在方法中使用类。
猜你喜欢
  • 2017-02-22
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 2018-07-09
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
相关资源
最近更新 更多