CA1024:在适用处使用属性
类型名 |
UsePropertiesWhereAppropriate |
CheckId |
CA1024 |
类别 |
Microsoft.Design |
是否重大更改 |
是 |
原因
公共或受保护方法的名称以 Get 开头,没有采用任何参数或返回的值不是数组。
规则说明
在大多数情况下,属性代表数据,而方法执行操作。 访问属性的方式与访问字段的方式相似,因此使用它们更容易。 如果存在下列条件之一,方法就很适于成为属性:
不采用任何参数并返回对象的状态信息。
接受单个参数来设置对象的部分状态。
属性的表现应当与字段一样;如果该方法不是这样,则不应将其更改为属性。 在下列情况下,方法比属性更好:
方法执行耗时的操作。 与设置或获取字段值所需的时间相比,此方法的速度明显较慢。
方法执行转换。 访问字段不会返回它所存储的数据的转换版本。
Get 方法会产生明显副作用。 检索字段的值不会产生任何副作用。
执行的顺序很重要。 设置字段的值并不依赖于其他操作的发生。
连续调用两次方法会产生不同的结果。
方法是静态的,但返回了调用方可更改的对象。 调用方不能通过检索某字段的值来更改该字段存储的数据。
方法返回数组。
如何解决冲突
要修复与该规则的冲突,请将方法更改为属性。
何时禁止显示警告
如果方法至少满足上文中列出的一个条件,则禁止显示与该规则有关的警告。
在调试器中控制属性扩展
程序员避免使用属性的一个原因,是他们不希望调试器自动展开属性。 例如,属性可能涉及分配一个大型对象或调用 P/Invoke,但它实际上可能不具有任何明显的副作用。
通过应用 System.Diagnostics.DebuggerBrowsableAttribute 可以阻止调试器自动展开属性。 下面的示例演示如何将此特性应用到实例属性。
Imports System
Imports System.Diagnostics
Namespace Microsoft.Samples
Public Class TestClass
' [...]
<DebuggerBrowsable(DebuggerBrowsableState.Never)> _
Public ReadOnly Property LargeObject() As LargeObject
Get
' Allocate large object
' [...]
End Get
End Property
End Class
End Namespace
using System;
using System.Diagnostics;
namespace Microsoft.Samples
{
public class TestClass
{
// [...]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public LargeObject LargeObject
{
get
{
// Allocate large object
// [...]
}
}
}
示例
下面的示例包含多个应转换为属性的方法,还包含多个由于表现与字段不同而不应转换的方法。
using System;
using System.Globalization;
using System.Collections;
namespace DesignLibrary
{
// Illustrates the behavior of rule:
// UsePropertiesWhereAppropriate.
public class Appointment
{
static long nextAppointmentID;
static double[] discountScale = {5.0, 10.0, 33.0};
string customerName;
long customerID;
DateTime when;
// Static constructor.
static Appointment()
{
// Initializes the static variable for Next appointment ID.
}
// This method will violate the rule, but should not be a property.
// This method has an observable side effect.
// Calling the method twice in succession creates different results.
public static long GetNextAvailableID()
{
nextAppointmentID++;
return nextAppointmentID - 1;
}
// This method will violate the rule, but should not be a property.
// This method performs a time-consuming operation.
// This method returns an array.
public Appointment[] GetCustomerHistory()
{
// Connect to a database to get the customer's appointment history.
return LoadHistoryFromDB(customerID);
}
// This method will violate the rule, but should not be a property.
// This method is static but returns a mutable object.
public static double[] GetDiscountScaleForUpdate()
{
return discountScale;
}
// This method will violate the rule, but should not be a property.
// This method performs a conversion.
public string GetWeekDayString()
{
return DateTimeFormatInfo.CurrentInfo.GetDayName(when.DayOfWeek);
}
// These methods will violate the rule, and should be properties.
// They each set or return a piece of the current object's state.
public DayOfWeek GetWeekDay ()
{
return when.DayOfWeek;
}
public void SetCustomerName (string customerName)
{
this.customerName = customerName;
}
public string GetCustomerName ()
{
return customerName;
}
public void SetCustomerID (long customerID)
{
this.customerID = customerID;
}
public long GetCustomerID ()
{
return customerID;
}
public void SetScheduleTime (DateTime when)
{
this.when = when;
}
public DateTime GetScheduleTime ()
{
return when;
}
// Time-consuming method that is called by GetCustomerHistory.
Appointment[] LoadHistoryFromDB(long customerID)
{
ArrayList records = new ArrayList();
// Load from database.
return (Appointment[])records.ToArray();
}
}
}