views:

235

answers:

4

Consider:

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

But this:

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

The real issue I have is that I'd like to have a function that depending on a parameter type, processes them differently. Such as:

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

and you can't make the following calls:

foo(123456U);
foo(123456);

I know there are ways to do this using generics. But I'm using .net micro framework and generics are not supported. But any C# 3.0 compiler specific features are supported including anonymous functions.

Edit I'd like to avoid having to handle each type separately. Is there a way this can be done and still have a parameter of object type?

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

the reason you can't unbox as int is because unboxing and casting are two different operations that happen to share the same operator.

Jimmy
I figured as much. Is there a way to get the same result without having to handle each type separately?
MandoMando
yes, see shuggy's answer
Jimmy
+2  A: 

This is because you can only unbox to the same type that was originally boxed (or to the nullable version of that type).

For example, a boxed byte can only be unboxed to byte or byte?, a boxed int can only be unboxed to int or int?, a boxed long can only be unboxed to long or long? etc etc.

LukeH
+3  A: 

The unbox operations support only the unbox, not any coercion that you might expect.

Whilst this can be frustrating it is worth noting that fixing this would

  1. make unboxing considerably more expensive
  2. possibly complicate the language due to nasty edge cases on method overload selection

Amongst others, for some in depth explanation, Eric Lippert is, as ever, most instructive

If you care about performance the only effective way to do this is (as Jimmy points out)

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

This seems not too onerous.

If this is too painful then you may make use of Convert.ToInt64 or Convert.ToUInt64() with the associated cost.

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

If Convert is not available here is the rotor source for the relevant methods:

    [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 is supported as an interface in the compact framework, I would assume this would therefore work but have not tried it.

If you want the MicroFramework then I suggest simply implementing the conversion options on a per type basis is the best you can do. The API is so sparse that there really isn't much else possible. I would also suggest that anything based on boxing is risky since this is a significant allocation overhead in a very memory constrained environment.

If you are trying to implement a string.Format() alike have you considered System.Ext.Text.StringBuilder.AppendFormat followed by a ToString?

ShuggyCoUk
@ShuggyCoUk Thanks! Unfortunately Convert class is not available in .net micro. And there are about 11 numeric types that would then require specific cases. There isn't a simple way of doing this, is there?
MandoMando
You could always create your own Convert helpers and then use that.
David Thibault
@David Thibault. This actually is part of a helper function for a string.Format :) I was trying to avoid re-writing more .net classes that already exist in full-framework.
MandoMando
@ShuggyCoUk thanks for update on IConvertible. It's available in Compact framework, but apparently not in Micro.http://msdn.microsoft.com/en-us/library/system.iconvertible.aspxI just fed the code to the compiler and it doesn't resolve IConvertible. Thanks for the huge effort. +1
MandoMando
see edit for the StringBuilder...
ShuggyCoUk
@ShuggyCoUk .Net Micro comes with only the bare bones to run in tiny spaces (56Kb mem). We have full C# 3.0 compiler support, but not features that require libraries such as generics, linq, IConvertible, and StringBuilder. This is obviously to save space. So some of us who can afford extra few kb, will have to roll our own StringBuilder which is the original cause leading to this question. I'm going to hold my nose and call the original switch statement as the "solution" in this particular case.
MandoMando
note that Micro is now open source so you might find most of your switch statement already written inside the Ext.StringBuilder for you at least. Good luck with your project
ShuggyCoUk
@ShuggyCoUk thanks! Yes, the source is open now, and I have mixed feelings about it since it's tempting to modify it and have to re-jig with every release.
MandoMando
you could simply lift the code into your own project (assuming licensing restrictions are okay) then you have what you need, but only that perhaps reducing the heavy dependency to something you can take.
ShuggyCoUk
A: 

You could create an extension method like that :

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

You could then use it as follows :

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