Field DesignÂ
Fields hold data associated with an object. In the vast majority of scenarios any non-static fields in a library should not be visible to developers. The following guidelines help you correctly use fields in your library design.
Do not provide instance fields that are public or protected.
Public and protected fields do not version well and are not protected by code access security demands. Instead of using publicly visible fields, use private fields and expose them through properties.
Do use constant fields for constants that will never change.
For example, the Math class defines E and PI as static constants.
The compiler inserts the values of const fields directly into the calling code, which means that const values can never be changed without the risk of introducing a compatibility issue.
Do use public static read-only fields for predefined object instances.
For example, the DateTime class provides static read-only fields that you can use to obtain DateTime objects set to the maximum or minimal time value. See MaxValue and MinValue.
Do not assign instances of mutable types to read-only fields.
The objects created using a mutable type can be modified after they are created. For example, arrays and most collections are mutable types while Int32, Uri, and String are immutable types. For fields that hold a mutable reference type, the read-only modifier prevents the field value from being overwritten but does not protect the mutable type from modification.
The following code example demonstrates the problem with using read-only fields. The BadDesign
class creates a read-only field and exposes it using a read-only property. This does not prevent the ShowBadDesign
class from modifying the contents of the read-only field.
Imports System
Namespace Examples.DesignGuidelines.Fields
Public Class BadDesign
Public Readonly dataValues as Integer() = {1,2,3}
Public ReadOnly Property Data as Integer ()
Get
Return dataValues
End Get
End Property
Public Sub WriteData()
For Each i as Integer In dataValues
Console.Write ("{0} ", i)
Next i
Console.WriteLine()
End Sub
End Class
Public Class ShowBadDesign
Public Shared Sub Main()
Dim bad as BadDesign = new BadDesign()
' The following line will write: 1 2 3
bad.WriteData()
Dim badData as Integer() = bad.Data
For i as Integer = 0 To badData.Length -1
badData(i) = 0
Next i
' The following line will write: 0 0 0
' because bad's data has been modified.
bad.WriteData()
End Sub
End Class
End Namespace
using System;
namespace Examples.DesignGuidelines.Fields
{
public class BadDesign
{
public readonly int[] data = {1,2,3};
public int [] Data
{
get {return data;}
}
public void WriteData()
{
foreach (int i in data)
{
Console.Write ("{0} ", i);
}
Console.WriteLine();
}
}
public class ShowBadDesign
{
public static void Main()
{
BadDesign bad = new BadDesign();
// The following line will write: 1 2 3
bad.WriteData();
int[] badData = bad.Data;
for (int i = 0; i< badData.Length; i++)
{
badData[i] = 0;
}
// The following line will write: 0 0 0
// because bad's data has been modified.
bad.WriteData();
}
}
}
Portions Copyright 2005 Microsoft Corporation. All rights reserved.
Portions Copyright Addison-Wesley Corporation. All rights reserved.
For more information on design guidelines, see the "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" book by Krzysztof Cwalina and Brad Abrams, published by Addison-Wesley, 2005.
See Also
Other Resources
Member Design Guidelines
Design Guidelines for Developing Class Libraries