在 .NET 9 中使用 INumber<T> 优化从 TSource 到 TDestination 的转换

问题描述 投票:0回答:1

我正在研究一种方法,以安全且优化的方式将 TSource 类型的数值转换为另一个数值类型 TDestination。我正在使用 .NET 9 以及 .NET 中引入的通用 INumber 和 IMinMaxValue 接口。

这是我当前的实现:

public static TDestination ToNumberOrDefault<TSource, TDestination>(this TSource number, TDestination defaultValue)
    where TSource : struct, INumber<TSource>, IMinMaxValue<TSource>
    where TDestination : struct, INumber<TDestination>, IMinMaxValue<TDestination>
{
    try
    {
        return TDestination.CreateChecked(number);
    }
    catch 
    {
        return defaultValue;
    }
}

问题: 性能问题:CreateChecked 方法似乎在执行转换之前在内部将源值转换为对象,这会引入装箱和拆箱开销,使其不太理想。 频繁使用:此方法在性能关键的代码路径中被频繁调用,因此我正在寻找更快的替代方案。

以 Int32.cs 中的代码为例:

else if (typeof(TOther) == typeof(long))
 {
     long actualValue = (long)(object)value;
     result = checked((int)actualValue);
     return true;
 }

问题: 是否有更优化的方法来执行 TSource 和 TDestination 之间的这种类型转换,同时确保值落在 TDestination 的有效范围内? 我是否可以避免使用 try/catch 块和 CreateChecked,同时仍确保该值被安全转换或在无效时回退到默认值? .NET 9 中是否有更适合此类数字转换的替代 API 或模式。

限制: TSource 和TDestination 保证实现INumber 和IMinMaxValue。 在执行转换之前,我需要确保 TSource 的值在 TDestination.MinValue 和 TDestination.MaxValue 定义的范围内。

用法示例:

var sourceValue = 12345;
var result = sourceValue.ToNumberOrDefault<int, short>(default(short)); // Should return short value or fallback to default

我尝试过的: 使用 CreateChecked:可以工作,但由于装箱/拆箱而引入性能问题。 使用 Convert.ChangeType:与装箱/拆箱和潜在开销类似的问题。 手动转换为中间类型(例如双精度或小数)以进行范围检查:增加复杂性和潜在的精度问题。

performance .net-core optimization .net-9.0 c#-13.0
1个回答
0
投票

问题:性能问题:

CreateChecked
方法似乎在执行转换之前在内部将源值转换为对象,这会引入装箱和拆箱开销,使其不太理想

这里不存在性能问题,因为这里不会发生分配,将为传递给泛型参数的每个不同值类型编译泛型,并且 JIT 编译器足够聪明,不会执行额外的工作(装箱、转换等)。临时猫到

object
(即在
(long)(object)value;
中)实际上是使用泛型时非常常见的技巧。

您可以轻松检查您的方法是否实际上不会分配:

int i = 0;
int k = 100L.ToNumberOrDefault(1); // "warm up"

var totalAllocatedBytes = GC.GetTotalAllocatedBytes(true);

for (int j = 0; j < 10_000; j++)
{
    i = 100L.ToNumberOrDefault(1);
}

Console.WriteLine(GC.GetTotalAllocatedBytes(true) - totalAllocatedBytes);

这为我打印了

0
。对于实际性能测试,我建议使用类似
BenchmarkDotNet
的东西,它具有分配诊断功能(通过
DotMemoryDiagnoser

或者例如通过 sharplab.io

检查 JIT 程序集
© www.soinside.com 2019 - 2024. All rights reserved.