CA1024: 適切な場所にプロパティを使用します

プロパティ
ルール ID CA1024
Title 適切な場所にプロパティを使用します
[カテゴリ] デザイン
修正が中断ありか中断なしか あり
.NET 8 では既定で有効 いいえ

原因

メソッドが Get で始まる名前を持ち、パラメーターを受け取らず、配列でない値を返します。

既定では、この規則の対象は外部から参照可能なメンバーのみですが、これは構成可能です。

規則の説明

ほとんどの場合は、プロパティによってデータを表し、メソッドによってアクションが実行されます。 プロパティにはフィールドのようにアクセスできるため、簡単に使用できます。 次の条件のいずれかに該当する場合は、メソッドをプロパティにすることをお勧めします。

  • メソッドでは引数を受け取らず、あるオブジェクトの状態情報を返す。
  • メソッドでは 1 つの引数を受け取り、あるオブジェクトの状態の一部を設定する。

違反の修正方法

この規則の違反を修正するには、メソッドをプロパティに変更します。

警告を抑制する条件

メソッドが次のいずれかの条件を満たしている場合は、この規則からの警告を非表示にします。 このような状況では、プロパティよりもメソッドの方が適しています。

  • メソッドをフィールドとして動作させることができない。
  • メソッドで時間のかかる操作を実行する。 フィールドの値を設定または取得するために必要な時間よりも、メソッドは明らかに遅くなります。
  • メソッドで変換を実行する。 フィールドにアクセスしても、格納されているデータの変換されたバージョンが返されることはありません。
  • Get メソッドに目に見える副作用がある。 フィールドの値を取得しても、副作用が発生することはありません。
  • 実行順序が重要である。 フィールドの値の設定は、他の操作の発生に依存しません。
  • メソッドを連続して 2 回呼び出すと、異なる結果が生成される。
  • メソッドは static だが、呼び出し元が変更できるオブジェクトが返される。 フィールドの値の取得では、呼び出し元がフィールドに格納されているデータを変更することはできません。
  • メソッドによって配列が返される。

警告を抑制する

単一の違反を抑制するだけの場合は、ソース ファイルにプリプロセッサ ディレクティブを追加して無効にしてから、規則をもう一度有効にします。

#pragma warning disable CA1024
// The code that's violating the rule is on this line.
#pragma warning restore CA1024

ファイル、フォルダー、またはプロジェクトの規則を無効にするには、構成ファイルでその重要度を none に設定します。

[*.{cs,vb}]
dotnet_diagnostic.CA1024.severity = none

詳細については、「コード分析の警告を抑制する方法」を参照してください。

分析するコードを構成する

次のオプションを使用して、コードベースのどの部分に対してこの規則を実行するか構成します。

このオプションを構成できる対象は、この規則だけ、それを適用するすべての規則、それを適用するこのカテゴリ (デザイン) のすべての規則のいずれかです。 詳細については、「コード品質規則の構成オプション」を参照してください。

特定の API サーフェイスを含める

ユーザー補助に基づいて、この規則を実行するコードベースの部分を構成できます。 たとえば、非パブリック API サーフェイスでのみ規則を実行するように指定するには、プロジェクトの .editorconfig ファイルに次のキーと値のペアを追加します。

dotnet_code_quality.CAXXXX.api_surface = private, internal

次の例には、プロパティに変換すべきいくつかのメソッドと、フィールドのように動作しないため変換すべきでないいくつかのメソッドが含まれています。

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 violates 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 violates 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 violates 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 violates the rule, but should not be a property.
    // This method performs a conversion.
    public string GetWeekDayString()
    {
        return DateTimeFormatInfo.CurrentInfo.GetDayName(when.DayOfWeek);
    }

    // These methods 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();
    }
}
Public Class Appointment
    Shared nextAppointmentID As Long
    Shared discountScale As Double() = {5.0, 10.0, 33.0}
    Private customerName As String
    Private customerID As Long
    Private [when] As Date

    ' Static constructor.
    Shared Sub New()
        ' Initializes the static variable for Next appointment ID.
    End Sub

    ' This method violates 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 Shared Function GetNextAvailableID() As Long
        nextAppointmentID += 1
        Return nextAppointmentID - 1
    End Function

    ' This method violates the rule, but should not be a property.
    ' This method performs a time-consuming operation. 
    ' This method returns an array.
    Public Function GetCustomerHistory() As Appointment()
        ' Connect to a database to get the customer's appointment history.
        Return LoadHistoryFromDB(customerID)
    End Function

    ' This method violates the rule, but should not be a property.
    ' This method is static but returns a mutable object.
    Public Shared Function GetDiscountScaleForUpdate() As Double()
        Return discountScale
    End Function

    ' This method violates the rule, but should not be a property.
    ' This method performs a conversion.
    Public Function GetWeekDayString() As String
        Return DateTimeFormatInfo.CurrentInfo.GetDayName([when].DayOfWeek)
    End Function

    ' These methods violate the rule and should be properties.
    ' They each set or return a piece of the current object's state.

    Public Function GetWeekDay() As DayOfWeek
        Return [when].DayOfWeek
    End Function

    Public Sub SetCustomerName(customerName As String)
        Me.customerName = customerName
    End Sub

    Public Function GetCustomerName() As String
        Return customerName
    End Function

    Public Sub SetCustomerID(customerID As Long)
        Me.customerID = customerID
    End Sub

    Public Function GetCustomerID() As Long
        Return customerID
    End Function

    Public Sub SetScheduleTime([when] As Date)
        Me.[when] = [when]
    End Sub

    Public Function GetScheduleTime() As Date
        Return [when]
    End Function

    ' Time-consuming method that is called by GetCustomerHistory.
    Private Function LoadHistoryFromDB(customerID As Long) As Appointment()
        Dim records As ArrayList = New ArrayList()
        Return CType(records.ToArray(), Appointment())
    End Function
End Class

デバッガーでのプロパティの展開を制御する

プログラマがプロパティの使用を避ける理由の 1 つは、デバッガーによって自動展開されないようにするためです。 たとえば、プロパティは大きなオブジェクトの割り当てや P/Invoke の呼び出しに関与する可能性がありますが、実際には目に見える副作用がないかもしれません。

System.Diagnostics.DebuggerBrowsableAttribute を適用することで、デバッガーによるプロパティの自動展開を防止することができます。 この属性をインスタンス プロパティに適用する例を次に示します。

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.Diagnostics;

namespace Microsoft.Samples
{
    class TestClass
    {
        // [...]

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public LargeObject LargeObject
        {
            get
            {
                // Allocate large object
                // [...]
            }
        }
    }
}