没有装箱的泛型方法中的原始类型转换
Primitive type conversion in generic method without boxing
在对我们的一个应用程序进行分析时,我发现了这段代码:
public TOut GetValue<TIn, TOut>(Func<TIn> getter)
{
var value = getter();
// Do some stuff with the value
return (TOut)Convert.ChangeType(value, typeof(TOut));
}
TIn
和 TOut
是整数、双精度或字符串。
由于使用 int 或 double 时的装箱,这在分析会话中显示为堆分配的重要来源。 Convert.ChangeType
的输入值是装箱的,因为该方法需要一个对象,return 值是装箱的,原因相同。
我正在尝试优化这段代码,因为这种方法用于高吞吐量服务,在这种情况下,这种分配是禁止的。理想情况下,我会将该方法重写为非泛型,但 API 被各种团队广泛使用,如此规模的重构将需要数月时间。与此同时,我正在努力缓解这个问题,并找到一种在不更改 API 合同的情况下改善情况的方法。但是我已经为此苦苦挣扎了一段时间,还没有找到解决方案。
给定方法契约,您知道一种无需装箱即可处理 int -> double 和 double -> int 转换的方法吗?请注意,我无法更改参数,但我可以添加通用约束(例如 where TIn : IConvertible
,但这对我帮助不大)。
如果您只需要专门化几个转换,我认为以下方法有效并且不会产生任何每次调用分配:
private static int FromDouble(double other)
{
return (int)other;
}
private static double FromInt(int other)
{
return (double)other;
}
private static Func<double, int> di = FromDouble;
private static Func<int, double> id = FromInt;
public TOut GetValue<TIn, TOut>(Func<TIn> getter)
{
var value = getter();
// Do some stuff with the value
if (typeof(TIn) == typeof(int) && typeof(TOut) == typeof(double))
{
var gf = (Func<TIn, TOut>)(object)id;
return gf(value);
}else if (typeof(TIn) == typeof(double) && typeof(TOut) == typeof(int))
{
var gf = (Func<TIn, TOut>)(object)di;
return gf(value);
}
return (TOut)Convert.ChangeType(value, typeof(TOut));
}
当然,还可以对此进行一些进一步的调整。
在对我们的一个应用程序进行分析时,我发现了这段代码:
public TOut GetValue<TIn, TOut>(Func<TIn> getter)
{
var value = getter();
// Do some stuff with the value
return (TOut)Convert.ChangeType(value, typeof(TOut));
}
TIn
和 TOut
是整数、双精度或字符串。
由于使用 int 或 double 时的装箱,这在分析会话中显示为堆分配的重要来源。 Convert.ChangeType
的输入值是装箱的,因为该方法需要一个对象,return 值是装箱的,原因相同。
我正在尝试优化这段代码,因为这种方法用于高吞吐量服务,在这种情况下,这种分配是禁止的。理想情况下,我会将该方法重写为非泛型,但 API 被各种团队广泛使用,如此规模的重构将需要数月时间。与此同时,我正在努力缓解这个问题,并找到一种在不更改 API 合同的情况下改善情况的方法。但是我已经为此苦苦挣扎了一段时间,还没有找到解决方案。
给定方法契约,您知道一种无需装箱即可处理 int -> double 和 double -> int 转换的方法吗?请注意,我无法更改参数,但我可以添加通用约束(例如 where TIn : IConvertible
,但这对我帮助不大)。
如果您只需要专门化几个转换,我认为以下方法有效并且不会产生任何每次调用分配:
private static int FromDouble(double other)
{
return (int)other;
}
private static double FromInt(int other)
{
return (double)other;
}
private static Func<double, int> di = FromDouble;
private static Func<int, double> id = FromInt;
public TOut GetValue<TIn, TOut>(Func<TIn> getter)
{
var value = getter();
// Do some stuff with the value
if (typeof(TIn) == typeof(int) && typeof(TOut) == typeof(double))
{
var gf = (Func<TIn, TOut>)(object)id;
return gf(value);
}else if (typeof(TIn) == typeof(double) && typeof(TOut) == typeof(int))
{
var gf = (Func<TIn, TOut>)(object)di;
return gf(value);
}
return (TOut)Convert.ChangeType(value, typeof(TOut));
}
当然,还可以对此进行一些进一步的调整。