在 C#/.NET 中将值类型作为引用类型传递时如何获得最佳性能?
如果您必须将值类型传递给方法,但由于某种原因,它必须作为引用类型传递,那么以下方式是否更快:
- 将其作为
object
传递 - 作为
ValueType 传递
- 将其作为通用包装器传递,
我在下面放置了一些示例代码来准确演示我的意思:
public class Program
{
public void Main()
{
var client = new IncrementedValueGetter();
int i = 8675309;
var byObject = client.IncrementObject(i);
var byValueType = client.IncrementValueType(i);
var byWrapper = client.IncrementWrapped(new ValueWrapper<int>(i));
}
}
public class IncrementedValueGetter
{
public int IncrementObject(object boxedValue)
{
return ((int)boxedValue) + 1;
}
public int IncrementValueType(ValueType boxedValueType)
{
return ((int) boxedValueType) + 1;
}
public int IncrementWrapped(ValueWrapper<int> valueWrapper)
{
return valueWrapper.Value + 1;
}
}
public class ValueWrapper<T>
where T: struct
{
private readonly T _value;
public ValueWrapper(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}
If you must pass a value type to a method, but for some reason, it must be passed as a reference type, is it faster to:
- Pass it as an
object
- Pass is as a
ValueType
- Pass it as a generic wrapper
I put some example code below to demonstrate exactly what I mean:.
public class Program
{
public void Main()
{
var client = new IncrementedValueGetter();
int i = 8675309;
var byObject = client.IncrementObject(i);
var byValueType = client.IncrementValueType(i);
var byWrapper = client.IncrementWrapped(new ValueWrapper<int>(i));
}
}
public class IncrementedValueGetter
{
public int IncrementObject(object boxedValue)
{
return ((int)boxedValue) + 1;
}
public int IncrementValueType(ValueType boxedValueType)
{
return ((int) boxedValueType) + 1;
}
public int IncrementWrapped(ValueWrapper<int> valueWrapper)
{
return valueWrapper.Value + 1;
}
}
public class ValueWrapper<T>
where T: struct
{
private readonly T _value;
public ValueWrapper(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
前两个实际上是等价的,只是生成标准的
box
IL。第三个需要构建包装类,这可能比盒子调用更昂贵。The first two are actually equivalent, and just generate the standard
box
IL. The third one requires the construction of your wrapper class, which is likely more expensive than the box call.这三种类型的性能可能相当,因为最终值类型必须以引用类型表示,这意味着在某些时候进行装箱。但不必要的开销和包装会让事情变得更糟。
关于装箱,要认识到的重要一点是,它本身并不昂贵,只是在特定的情况下相对昂贵,例如在紧密循环中装箱和拆箱。尝试关注为什么不能使用值类型本身以及为什么需要使用引用类型,并让它指导您的设计。您希望如何从引用类型访问值类型。引用类型会包含其他引用类型吗?等等。
最重要的是,如果您真的担心,只需编写代码并进行测量即可。如果它对性能至关重要并且您的应用程序不断发展,请在应用程序的上下文中继续对其进行测量。
The performance is probably comparable for all three since ultimately a value type must be represented in a reference type which means boxing at some point. But you can make things worse with unnecessary overhead and wrapping.
The important thing to realize about boxing is that it is not inherently expensive, it is only relatively expensive in context of something specific like boxing and unboxing in a tight loop. Try to focus on why you cannot use the the value type itself and why you need to use a reference type and let that guide your design. How would you like to access the value type from the reference type. Will the reference type hold other reference types? And so on.
Above all, if you're really concerned, just code it up and measure it. And keep measuring it in the context of your application, if it is performance critical, and you application evolves.