如何在不装箱/拆箱的情况下处理已知的泛型类型

Mar*_*son 3 c# generics

我有一个处理大量各种类型数据的通用方法。

当数据是特定类型时(在本例中),我想应用一些额外的处理double。不同类型的所有其他功能都是相同的。

有没有比下面示例中所示的(非常慢)装箱/拆箱更好的方法?

这似乎意味着我们需要让编译器相信Tdouble是相同的类型,在if..else断言这一点的部分中。

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;
}
Run Code Online (Sandbox Code Playgroud)

实际功能显然比这个例子更复杂。

需要在 .NET Framework 和 .NET 6 中工作。

Jim*_*jim 6

您可以使用as运算符而不是 进行转换(T)

  • 在表达式中,如果可能的话,value as T它将尝试转换value为类型T,否则值将为null
  • as仅当转换为引用类型(在您的情况下为数组)时才可用。

您还可以使用is运算符来替换类型检查。

  • 在表达式中,如果可以转换为类型,value is T则表达式将为 true 。valueT
  • 在表达式中,如果可以转换为类型,则value as T tValue表达式将为 true ,并且变量将被赋予 的值。valueTtValue(T)value

使用这些运算符更新您的代码,我们得到:

  • 如果在 .Net Framework 或 .Net 中,可空引用类型被禁用:
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;
}
Run Code Online (Sandbox Code Playgroud)
  • 如果在 .Net 中启用了可空引用类型:
  • 这使用null-forgiving 运算符!来告诉编译器as T[]永远不会返回null
    • 当启用可空引用类型时,as T[]结果是 ,T[]?因为如果转换失败,结果是null
    • 我们知道它不会产生结果,null因为我们知道它T是一个doublefrom data is double[],所以我们可以安全地使用它。
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;
}
Run Code Online (Sandbox Code Playgroud)