C# generics: cast generic type to value type

First off, this is a really bad code smell. Any time you're doing a type test on a type parameter like this odds are good you're abusing generics.

The C# compiler knows that you are abusing generics in this way and disallows the cast from the value of type T to int, etc. You can turn off the compiler getting in your way by casting the value to object before you cast it to int:

return BitConverter.GetBytes((int)(object)this._value);

Yuck. Again, it would be better to find another way to do this. For example:

public class NumericValue
{
    double value;
    enum SerializationType { Int, UInt, Double, Float };
    SerializationType serializationType;        

    public void SetValue(int value)
    {
        this.value = value;
        this.serializationType = SerializationType.Int
    }
    ... etc ...

    public byte[] GetBytes()
    {
        switch(this.serializationType)
        {
            case SerializationType.Int:
                return BitConverter.GetBytes((int)this.value);
            ... etc ...

No generics necessary. Reserve generics for situations that are actually generic. If you've written the code four times one for each kind of type, you haven't gained anything with generics.


Well, it strikes me that the type really isn't properly generic to start with: it can only be one of a few types, and you can't express that constraint.

Then you want to call a different overload of GetBytes based on the type of T. Generics doesn't work well for that sort of thing. You could use dynamic typing to achieve it, in .NET 4 and above:

public byte[] GetBytes()
{
    return BitConverter.GetBytes((dynamic) _value);
}

... but again this doesn't really feel like a nice design.


Pretty late answer, but anyways... there is a way to make it slightly nicer... Make use of generics in a this way: Implement another generic type which converts the types for you. So you don't have to care about unboxing, casting etc of the type to object... it will just work.

Also, in your GenericClass, now you don't have to switch the types, you can just use IValueConverter<T> and also cast it as IValueConverter<T>. This way, generics will do the magic for you to find the correct interface implementation, and in addition, the object will be null if T is something you do not support...

interface IValueConverter<T> where T : struct
{
    byte[] FromValue(T value);
}

class ValueConverter:
    IValueConverter<int>,
    IValueConverter<double>,
    IValueConverter<float>
{
    byte[] IValueConverter<int>.FromValue(int value)
    {
        return BitConverter.GetBytes(value);
    }

    byte[] IValueConverter<double>.FromValue(double value)
    {
        return BitConverter.GetBytes(value);
    }

    byte[] IValueConverter<float>.FromValue(float value)
    {
        return BitConverter.GetBytes(value);
    }
}

public class GenericClass<T> where T : struct
{
    T _value;

    IValueConverter<T> converter = new ValueConverter() as IValueConverter<T>;

    public void SetValue(T value)
    {
        this._value = value;
    }

    public byte[] GetBytes()
    {
        if (converter == null)
        {
            throw new InvalidOperationException("Unsuported type");
        }

        return converter.FromValue(this._value);
    }
}