1. 避免调用需要Unboxing
翻译概述:
在Java和C#中,所有的数据类型都是从System.Object继承来的,包括数值型类型。这样的设计使我们可以用相同的方式处理引用类型和值类型。从而为我们提供了很大的灵活性,实现更加通用的算法。
但是,将所有数据都放在堆中进行管理无疑会降低程序的性能。因此,C#(包括Java)中都将数据类型分为值类型和引用类型,在常规状态下,值类型局部变量会放在栈中进行管理,从而实现更加高的效率。
这时候就存在将值类型转换为引用类型的问题,因为可能我们的方法只接受引用类型的参数。因此在C#和Java中都有Boxing和Unboxing的概念。当我们将一个值类型数据复制给一个引用性变量时,会将值类型数据作Boxing处理。在做反向操作时,进行Unboxing处理。相当于作了一个盒子来装这个这类型数据。
但是,正如下文中所说,做Unboxing操作会消耗更多的系统资源,因此,微软建议尽量避免进行Unboxing操作。
引起的原因:
调用一个返回object类型值得函数,并且将返回值转换为一个值类型。
描述:
将一个object实例转换为之类型会调用Unboxing操作。当调用Unboxing操作时,运行时系统会首先判断这个object实例是否是空引用,然后判断其中存储的数据是不是一个请求类型的数据。如果这两条都满足了,运行时系统会返回一个引用到其中存储的数据,并且将数据从堆中复制到栈中。这些操作会影响执行效率。
修复:
实现一个强类型的方法,并调用这个新方法。如果需要,可以使用范型来实现。
例外:
如果不能实现一个对应的强类型方法,可以忽略这条规则。如果性能并不是关心的重点,可以完全忽略这条规则。
例程:
下面的例子中包含一个方法"WeaklyTyped",这个方法违反了这条规则。例子中还包括另外一个方法”StronglyTyped”,它修正了这个问题。
下面的例子中包含一个方法”WeaklyTyped”,这个方法违反了这条规则,例子中还包括另外一个方法"UsesGenerics",它使用范型修正了这个问题。
代码见原文
原文引用:
Avoid calls that require unboxing
Rule Description Casting an Object instance to a value type invokes an unboxing operation. In an unboxing operation, the runtime first checks whether the instance is null and then determines whether the instance represents the specified value type. If so, the runtime returns a reference to the data portion of the instance and copies the fields from the heap to the stack. These operations degrade performance. How to Fix Violations To fix a violation of this rule, replace the call with an equivalent strongly typed method. Use generics if available. When to Exclude Messages Exclude a message from this rule if an equivalent strongly typed method is not available. It is also safe to exclude a message from this rule, or ignore the rule entirely, if performance is not a concern. Example Code The following example shows a method, WeaklyTyped, which violates the rule and a method, StronglyTyped, which satisfies the rule. [C#] using System; namespace PerformanceLibrary { public interface IWork { object DoWork(); } public class Work : IWork { object IWork.DoWork() { return 3; } public int DoWork() { return 3; } } public class NeedsWork { public void WeaklyTyped() { IWork iwork = new Work(); // The following call violates the rule. int x = (int)iwork.DoWork(); } public void StronglyTyped() { Work work = new Work(); int x = work.DoWork(); } } } The following example shows a method, WeaklyTyped, which violates the rule and a method, UsesGenerics, which satisfies the rule using generics. [C#] using System; using System.Collections; using System.Collections.Generic; namespace PerformanceLibrary { public class AvoidBoxing { public void WeaklyTyped() { ArrayList weaklyTypedList = new ArrayList(); weaklyTypedList.Add(3); weaklyTypedList.Add(5); weaklyTypedList.Add(11); int sum = 0; for(int i = 0; i < weaklyTypedList.Count; i++) { // The following call violates the rule. sum += (int)weaklyTypedList[i]; } } public void UsesGenerics() { List<int> stronglyTypedList = new List<int>(); stronglyTypedList.Add(3); stronglyTypedList.Add(5); stronglyTypedList.Add(11); int sum = 0; for(int i = 0; i < stronglyTypedList.Count; i++) { sum += stronglyTypedList[i]; } } } } [Visual Basic] Imports System Imports System.Collections Imports System.Collections.Generic Namespace PerformanceLibrary Public Class AvoidBoxing Sub WeaklyTyped() Dim weaklyTypedList As New ArrayList() weaklyTypedList.Add(3) weaklyTypedList.Add(5) weaklyTypedList.Add(11) Dim sum As Integer = 0 For I As Integer = 0 To weaklyTypedList.Count - 1 ' The following call violates the rule. sum = sum + DirectCast(weaklyTypedList(I), Integer) Next End Sub Sub UsesGenerics() Dim stronglyTypedList As New List(Of Integer) stronglyTypedList.Add(3) stronglyTypedList.Add(5) stronglyTypedList.Add(11) Dim sum As Integer = 0 For I As Integer = 0 To stronglyTypedList.Count - 1 sum = sum + DirectCast(stronglyTypedList(I), Integer) Next End Sub End Class End Namespace
|