C#为什么UInt32不能作为UInt64取消装箱?

时间:2009-11-23 23:49:55

标签: c#-3.0 .net-micro-framework

考虑一下:

object o = 123456U;
ulong l = (ulong) o; // fails

但是这个:

object o = 123456U;
ulong l = (ulong) (uint) o; // succeeds

我遇到的真正问题是,我希望有一个函数,根据参数类型,以不同的方式处理它们。如:

void foo(object o)
{
switch (Type.GetTypeCode(o.GetType()))
   {
      case TypeCode.UInt32:
      case TypeCode.UInt64:
      ulong l = (ulong) o;
      RunUnsignedIntVersion(l);
      break;
      case TypeCode.Int32:
      case TypeCode.Int64:
      long n = (long) o;
      RunSignedVersion(n);
      break;
   }
}

您无法拨打以下电话:

foo(123456U);
foo(123456);

我知道有很多方法可以使用泛型。但我使用.net微框架和泛型不受支持。但是支持任何C#3.0编译器特定功能,包括匿名函数。

编辑我想避免单独处理每种类型。有没有办法可以做到这一点,并且仍然有对象类型的参数?

4 个答案:

答案 0 :(得分:3)

  case TypeCode.Int32:
    RunSignedVersion((int) o);
    break;
  case TypeCode.Int64:
    long n = (long) o;
    RunSignedVersion(n);
    break;

你不能将unbox视为int的原因是因为拆箱和转换是两个不同的操作碰巧共享同一个操作符。

答案 1 :(得分:3)

unbox操作仅支持unbox,而不支持您可能期望的任何强制。

虽然这可能令人沮丧,但值得注意的是,解决这个问题

  1. 使拆箱相当更昂贵
  2. 由于方法过载选择上令人讨厌的边缘情况,可能会使语言复杂化
  3. 除其他外,对于一些深入解释,Eric Lippert一如既往地most instructive

    如果你关心表演,唯一有效的方法是(正如吉米指出的那样)

    case TypeCode.Int32:
        RunSignedVersion((int) o);
        break;
    case TypeCode.Int64:
        long n = (long) o;
        RunSignedVersion(n);
        break;
    

    这似乎并不太繁重。

    如果这太痛苦了,那么你可以使用Convert.ToInt64或Convert.ToUInt64()以及相关的费用。

    void foo(object o)
    {
       switch (Type.GetTypeCode(o.GetType()))
       {
          case TypeCode.UInt32:
          case TypeCode.UInt64:
              ulong l = Convert.ToUInt64(o);
              RunUnsignedIntVersion(l);
              break;
          case TypeCode.Int32:
          case TypeCode.Int64:
              long n = Convert.ToInt64(o);
              RunSignedVersion(n);
              break;
       }
    }
    

    如果转换不可用,则此处是相关方法的转子源:

        [CLSCompliant(false)]   
        public static ulong ToUInt64(object value) {
            return value == null? 0: ((IConvertible)value).ToUInt64(null);
        }
    
        [CLSCompliant(false)]   
        public static long ToInt64(object value) {
            return value == null? 0: ((IConvertible)value).ToInt64(null);
        }
    

    支持IConvertible作为紧凑框架中的接口,我认为这样可以工作,但没有尝试过。

    如果您需要MicroFramework,那么我建议您只需按类型实现转换选项即可。 API为so sparse,实际上没有其他可能性。我还建议基于装箱的任何东西都有风险,因为这是一个在内存受限的环境中的重要分配开销。

    如果您尝试实现string.Format(),您是否考虑过System.Ext.Text.StringBuilder.AppendFormat后跟ToString?

答案 2 :(得分:2)

这是因为您只能取消装入最初装箱的相同类型(或该类型的可空版本)。

例如,框装byte只能取消装箱到bytebyte?,装箱int只能取消装箱到int或{{ 1}},盒装int?只能取消装箱到longlong等等。

答案 3 :(得分:0)

您可以创建一个类似的扩展方法:

public static class ConversionExtensions
{
    public static ulong ToUInt64(this object value)
    {
        return ((IConvertible)value).ToUInt64();
    }
}

然后您可以按如下方式使用它:

object o = 123456U;
ulong l = o.ToUInt64();