代码改变世界

[FxCop.性能规则]1. 避免调用需要Unboxing

2005-08-10 21:20  Colin Han  阅读(1936)  评论(1编辑  收藏  举报

1.     避免调用需要Unboxing

翻译概述:

JavaC#中,所有的数据类型都是从System.Object继承来的,包括数值型类型。这样的设计使我们可以用相同的方式处理引用类型和值类型。从而为我们提供了很大的灵活性,实现更加通用的算法。

但是,将所有数据都放在堆中进行管理无疑会降低程序的性能。因此,C#(包括Java)中都将数据类型分为值类型和引用类型,在常规状态下,值类型局部变量会放在栈中进行管理,从而实现更加高的效率。

这时候就存在将值类型转换为引用类型的问题,因为可能我们的方法只接受引用类型的参数。因此在C#Java中都有BoxingUnboxing的概念。当我们将一个值类型数据复制给一个引用性变量时,会将值类型数据作Boxing处理。在做反向操作时,进行Unboxing处理。相当于作了一个盒子来装这个这类型数据。

但是,正如下文中所说,做Unboxing操作会消耗更多的系统资源,因此,微软建议尽量避免进行Unboxing操作。

 另外,据说C#的范型使用了一定的技术实现了值类型和引用类型同等处理的能力,没有使用BoxingUnboxing,因此效率和直接使用强类型方法相当。因此下文中的例子中演示了使用范型替代ArrayList来提高效率。

引起的原因:

调用一个返回object类型值得函数,并且将返回值转换为一个值类型。

描述:

将一个object实例转换为之类型会调用Unboxing操作。当调用Unboxing操作时,运行时系统会首先判断这个object实例是否是空引用,然后判断其中存储的数据是不是一个请求类型的数据。如果这两条都满足了,运行时系统会返回一个引用到其中存储的数据,并且将数据从堆中复制到栈中。这些操作会影响执行效率。

修复:

实现一个强类型的方法,并调用这个新方法。如果需要,可以使用范型来实现。

例外:

如果不能实现一个对应的强类型方法,可以忽略这条规则。如果性能并不是关心的重点,可以完全忽略这条规则。

例程:

下面的例子中包含一个方法"WeaklyTyped",这个方法违反了这条规则。例子中还包括另外一个方法”StronglyTyped”,它修正了这个问题。

 
代码见原文

 

下面的例子中包含一个方法”WeaklyTyped”,这个方法违反了这条规则,例子中还包括另外一个方法"UsesGenerics",它使用范型修正了这个问题。

 

代码见原文

 

原文引用:

Avoid calls that require unboxing

TypeName:

AvoidCallsThatRequireUnboxing

CheckId:

CA1808

Category:

Microsoft.Performance

Message Level:

Warning

Certainty:

90%

Breaking Change:

NonBreaking


Cause: A call is made to a method that returns a System.Object instance and the instance is cast to a value type.

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