Home > front end >  How to deal with known generic type without boxing/unboxing
How to deal with known generic type without boxing/unboxing

Time:11-04

I have a generic method dealing with large amounts of data of various types.

I'd like to apply some additional processing when the data is a specific type (double in this case). All other functionality is identical across the different types.

Is there a better way than the (very slow) box/unboxing illustrated in the example below?

This seems to imply that we need to convince the compiler that T and double are the same type, within the if..else section that asserts this.

public static T[] HalfIfDouble<T>(T[] data)
{
    T[] result;

    if (typeof(T) == typeof(double))
    {
        // result = data.Select(x => x * 0.5).ToArray(); // does not compile

        result = data.Select(x =>
        {
            double d = (double)(object)x;
            return (T)(object)(d * 0.5);
        }).ToArray();
    }
    else
    {
        result = data;
    }

    // do some more processing...

    return result;
}

The real functionality is obviously more complicated than this example.

Needs to work in .NET Framework and .NET 6.

CodePudding user response:

You can use the as operator to do the casting rather than (T).

  • In the expression value as T it will attempt to cast value to the type T if it's possible, otherwise the value will be null.
  • as is only available when casting to a reference type (in your case an array).

You can also use the is operator to replace the type check.

  • In the expression value is T the expression will be true if value can be cast to the type T.
  • In the expression value as T tValue the expression will be true if value can be cast to the type T and the variable tValue will be assigned the value of (T)value.

Updating your code with these operators we get:

  • If in .Net Framework or in .Net and nullable reference types are disabled:
public static T[] HalfIfDouble<T>(T[] data)
{
    T[] result;

    if (data is double[] da)
    {
        result = da.Select(x => x * 0.5).ToArray() as T[];
    }
    else
    {
        result = data;
    }

    // do some more processing...

    return result;
}
  • If in .Net and nullable reference types are enabled:
  • This uses the null-forgiving operator ! to to tell the compiler that as T[] will never return null.
    • When nullable reference types are enabled as T[] results in T[]? because if the cast fails the result is null.
    • We know that it won't result in null because we know T is a double from data is double[] so we can safely use this.
public static T[] HalfIfDouble<T>(T[] data)
{
    T[] result;

    if (data is double[] da)
    {
        result = (da.Select(x => x * 0.5).ToArray() as T[])!;
    }
    else
    {
        result = data;
    }

    // do some more processing...

    return result;
}
  • Related