Do not call properties that clone values in loops
TypeName |
DoNotCallPropertiesThatCloneValuesInLoops |
CheckId |
CA1817 |
Category |
Microsoft.Performance |
Breaking Change |
NonBreaking |
Cause
A method calls the get accessor of a property inside an iteration statement, such as a for or while loop, and the accessor returns a cloned object.
Rule Description
A cloned object is a new object created with a value identical to that of an existing object. A cloned object is retrieved from a call to the System.ICloneable.Clone method, which creates a new instance of its declaring type with a value identical to the current instance.
This rule warns about a property accessed inside an iteration statement when the property returns a cloned object. In this case, multiple identical objects are created. If this is not the intent, access the property outside the iteration statement. Otherwise, multiple unnecessary objects are created and afterward, these objects must be garbage collected. This degrades performance, especially in compact iteration statements.
How to Fix Violations
To fix a violation of this rule, assign the property to a local variable outside the iteration statement and use the local variable inside the iteration statement.
When to Exclude Warnings
Exclude a warning from this rule if the intent is to create the cloned values inside the iteration statement. It is also safe to exclude a warning from this rule, or ignore the rule entirely, if performance is not a concern.
Example
The following example shows two violations of this rule, one of which should be excluded, and a method, BetterPerformingMethod
, that satisfies the rule using a local variable to store the cloned value.
Imports System
Imports System.Collections
Namespace PerformanceLibrary
Public Class PropertyThatClones
Dim someList As New ArrayList()
Readonly Property List As ArrayList
Get
Return DirectCast(someList.Clone(), ArrayList)
End Get
End Property
Sub ModifyList(anything As Object)
someList.Add(anything)
End Sub
End Class
Public Class UseProperty
Dim cloner As PropertyThatClones
Dim arrayOfLists(10) As ArrayList
Sub New
cloner = New PropertyThatClones()
cloner.ModifyList("thirteen")
End Sub
' The following method violates the rule.
Sub UnderperformingMethod()
For I As Integer = 0 To 9
Console.WriteLine(cloner.List)
Next
End Sub
' The following method satisfies the rule.
Sub BetterPerformingMethod()
Dim localList As ArrayList = cloner.List
For I As Integer = 0 To 9
Console.WriteLine(localList)
Next
End Sub
' The following method violates the rule but the
' violation should be excluded because the array
' of identical ArrayList instances is intended.
Sub BuildArrayOfArrayLists()
For I As Integer = 0 To arrayOfLists.Length - 1
arrayOfLists(i) = cloner.List
Next
End Sub
End Class
End Namespace
using System;
using System.Collections;
namespace PerformanceLibrary
{
public class PropertyThatClones
{
ArrayList someList = new ArrayList();
public ArrayList List
{
get
{
return (ArrayList)someList.Clone();
}
}
public void ModifyList(object anything)
{
someList.Add(anything);
}
}
public class UseProperty
{
PropertyThatClones cloner;
ArrayList[] arrayOfLists;
public UseProperty()
{
cloner = new PropertyThatClones();
cloner.ModifyList("thirteen");
arrayOfLists = new ArrayList[10];
}
// The following method violates the rule.
public void UnderperformingMethod()
{
for(int i = 0; i < 10; i++)
{
Console.WriteLine(cloner.List);
}
}
// The following method satisfies the rule.
public void BetterPerformingMethod()
{
ArrayList localList = cloner.List;
for(int i = 0; i < 10; i++)
{
Console.WriteLine(localList);
}
}
// The following method violates the rule but the
// violation should be excluded because the array
// of identical ArrayList instances is intended.
public void BuildArrayOfArrayLists()
{
for(int i = 0; i < arrayOfLists.Length; i++)
{
arrayOfLists[i] = cloner.List;
}
}
}
}