3

In C# is a generic method that works on int and uint not possible because the generic type must be a class and not a primitive or is this only on constraints?

public decimal shift<T>(T input, byte b) where T : int, uint
{
   ///....
}

Is there anyway to make this work without the constraints?

public decimal shift<T>(T input, byte b)  
{
   ///....
}

When I do the latter, I get further but still error out on a bit shift operation on the int or uint. It's as though, it doesn't know what type it is at run time.

Matt
  • 25,943
  • 66
  • 198
  • 303

3 Answers3

2

In C#, writing special cases for native types is typically done by method overloading. There are several places in the BCL where you can see this kind of design, one example being the BitConverter class.

If you want a generic version with a few special cases, you can add a generic overload and C#'s type inference will make it transparent to the end user.

public decimal shift(int input, byte b)
{
    //....
}

public decimal shift(uint input, byte b)
{
    //....
}

public decimal shift<T>(T input, byte b)
{
    //....
}

Usage:

shift(5, 1); //resolves to the 'int'overload
shift(5u, 1); //resolves to the 'uint' overload
shift(new Point(2, 2), 1) //resolves to the generic overload with T = Point

I'm guessing you're trying to do bit shifting with a generic method. There are only a handful of types that this makes sense for (byte, sbyte, short, ushort, int, uint, long, ulong), so you might as well just write out the 8 overloads. I have a class in one of my projects that includes a lot of bit hacks, and I just write out the necessary overloads and it works out pretty well.

Robert Rouhani
  • 14,512
  • 6
  • 44
  • 59
0

You have to use following code to make it working:

    public static decimal shift<T>(T input, byte b) where T : struct
    {
        return 1.0M;
    }

It is because int and uint are structs not classes

Piotr Stapp
  • 19,392
  • 11
  • 68
  • 116
  • I tried, it doesn't seem to fool the compiler: – Matt Jul 02 '13 at 04:25
  • 'int' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter. 'uint' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter. – Matt Jul 02 '13 at 04:28
  • It's in LinqPad (don't think it should matter) – Matt Jul 02 '13 at 04:29
  • I completly changed my answer. No it compiles without problems – Piotr Stapp Jul 02 '13 at 04:40
  • get an error when attempting to perform a shift (assuming this is actually what Matt wants to do) – Kevin Nacios Jul 02 '13 at 04:45
0

I think in this case, you'll have to check the type it is at runtime, but it would be more clear if you just had to overloaded methods that took an int and uint

public decimal shift<T>(T input, byte b)
{ 
    if (input is int)
        return (Convert.ToInt32(input) << b);
    else if (input is uint)
        return (Convert.ToByte(input) << b);
}

vs

public decimal shift(int input, byte b)
{ 
    return input << b;
}

public decimal shift(uint input, byte b)
{
    return input << b;
}
Kevin Nacios
  • 2,843
  • 19
  • 31