| TypeName | PropertiesShouldNotReturnArrays |
| CheckId | CA1819 |
| Category | Microsoft.Performance |
| Breaking Change | Breaking |
A public or protected property in a public type returns an array.
Arrays returned by properties are not write-protected, even if the property is read-only. To keep the array tamper-proof, the property must return a copy of the array. Typically, users will not understand the negative performance implications of calling such a property. Specifically, they might use the property as an indexed property.
To fix a violation of this rule, make the property a method.
Do not exclude a warning from this rule.
The following example shows a property that violates this rule. The Main method illustrates how a user might write poorly performing code using such a property.
Imports System Namespace PerformanceLibrary Public Class Test Private nameValues() As String Public Sub New() nameValues = New String(100) {} ' Loading string array with sample data. Dim i As Integer For i = 0 To 99 nameValues(i) = "Sample" Next i End Sub 'New ' Violates rule: PropertiesShouldNotReturnArrays. Public ReadOnly Property Names() As String() Get Return CType(nameValues.Clone(), String()) End Get End Property Public Shared Sub Main() ' Using the property in the following manner ' results in 201 copies of the array. ' One copy is made each time the loop executes, ' and one copy is made each time the condition is tested. Dim t As New Test() Dim i As Integer For i = 0 To t.Names.Length - 1 If t.Names(i) = "SomeName" Then ' Perform some operation. End If Next i End Sub 'Main End Class 'Test End Namespace
using System; namespace PerformanceLibrary { public class Test { string [] nameValues; public Test() { nameValues = new string[100]; // Loading string array with sample data. for (int i = 0; i< 100; i++) { nameValues[i] = "Sample"; } } // Violates rule: PropertiesShouldNotReturnArrays. public string [] Names { get { return (string[]) nameValues.Clone(); } } public static void Main() { // Using the property in the following manner // results in 201 copies of the array. // One copy is made each time the loop executes, // and one copy is made each time the condition is tested. Test t = new Test(); for (int i = 0; i < t.Names.Length ; i++) { if (t.Names[i] == ("SomeName")) { // Perform some operation. } } } } }
As a property this will be picked up automatically by the serializer. When converted to method calls, you have no way to get or set the values on the client.
Additionally, you cannot use IList based collections for SOAP messages.
Sometimes you want to allow the consumer of the class to modify property. The following example shows a read and write property that violates this rule.
[C#]
using System;
namespace PerformanceLibrary
{
public class Book
{
private string[] _Pages;
public Book(string[] pages)
{
_Pages = pages;
}
public string[] Pages
{
get { return _Pages; }
set { _Pages = value; }
}
}
}
[Visual Basic]
Imports System
Namespace PerformanceLibrary
Public Class Book
Private _Pages As String()
Public Sub New(ByVal pages As String())
_Pages = pages
End Sub
Public Property Pages() As String()
Get
Return _Pages
End Get
Set(ByVal value as String())
_Pages = value
End Set
End Property
End Class
End Namespace
The following example fixes the above violation by changing the property to return a Collection<String> (Collection(Of String) in Visual Basic).
[C#]
using System;
using System.Collections.ObjectModel;
namespace PerformanceLibrary
{
public class Book
{
private Collection<string> _Pages;
public Book(string[] pages)
{
_Pages = new Collection<string>(pages);
}
public Collection<string> Pages
{
get { return _Pages; }
}
}
}
[Visual Basic]
Imports System
Imports System.Collections.ObjectModel
Namespace PerformanceLibrary
Public Class Book
Private _Pages As Collection(Of String)
Public Sub New(ByVal pages As String())
_Pages = New Collection(Of String)(pages)
End Sub
Public ReadOnly Property Pages() As Collection(Of String)
Get
Return _Pages
End Get
End Property
End Class
End Namespace
Example of a property that violates this rule
The following example shows a property that violates this rule.
[C#]
using System;
namespace PerformanceLibrary
{
public class Book
{
private string[] _Pages;
public Book(string[] pages)
{
_Pages = pages;
}
public string[] Pages
{
get { return _Pages; }
}
}
}
[Visual Basic]
Imports System
Namespace PerformanceLibrary
Public Class Book
Private _Pages As String()
Public Sub New(ByVal pages As String())
_Pages = pages
End Sub
Public ReadOnly Property Pages() As String()
Get
Return _Pages
End Get
End Property
End Class
End Namespace
To fix a violation of this rule, either make the property a method or change the property to return a collection instead of the array.
Fixing this violation by changing the property to a method
The following example fixes the above violation by changing the property to a method.
[C#]
using System;
namespace PerformanceLibrary
{
public class Book
{
private string[] _Pages;
public Book(string[] pages)
{
_Pages = pages;
}
public string[] GetPages()
{
// Need to return a clone of the array so that consumers
// of this library cannot change its contents
return (string[])_Pages.Clone();
}
}
}
[Visual Basic]
Imports System
Namespace PerformanceLibrary
Public Class Book
Private _Pages As String()
Public Sub New(ByVal pages As String())
_Pages = pages
End Sub
Public Function GetPages() As String()
' Need to return a clone of the array so that consumers
' of this library cannot change its contents
Return DirectCast(_Pages.Clone(), String())
End Function
End Class
End Namespace
Fixing this violation by changing the property to return a collection
The following example fixes the above violation by changing the property to return a ReadOnlyCollection<String> (ReadOnlyCollection(Of String) in Visual Basic).
[C#]
using System;
using System.Collections.ObjectModel;
namespace PerformanceLibrary
{
public class Book
{
private ReadOnlyCollection<string> _Pages;
public Book(string[] pages)
{
_Pages = new ReadOnlyCollection<string>(pages);
}
public ReadOnlyCollection<string> Pages
{
get { return _Pages; }
}
}
}
[Visual Basic]
Imports System
Imports System.Collections.ObjectModel
Namespace PerformanceLibrary
Public Class Book
Private _Pages As ReadOnlyCollection(Of String)
Public Sub New(ByVal pages As String())
_Pages = New ReadOnlyCollection(Of String)(pages)
End Sub
Public ReadOnly Property Pages() As ReadOnlyCollection(Of String)
Get
Return _Pages
End Get
End Property
End Class
End Namespace