C# の自動プロパティにデフォルト値を与えるにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/40730

  •  09-06-2019
  •  | 
  •  

質問

C# の自動プロパティにデフォルト値を与えるにはどうすればよいですか?コンストラクターを使用するか、古い構文に戻します。

コンストラクターの使用:

class Person 
{
    public Person()
    {
        Name = "Default Name";
    }
    public string Name { get; set; }
}

通常のプロパティ構文の使用 (デフォルト値あり)

private string name = "Default Name";
public string Name 
{
    get 
    {
        return name;
    }
    set
    {
        name = value;
    }
}

もっと良い方法はありますか?

役に立ちましたか?

解決

C# 5 以前では、自動実装されたプロパティにデフォルト値を与えるには、コンストラクターで行う必要があります。

自動プロパティ初期化子を持つ機能は、C# 6.0 以降に含まれています。構文は次のとおりです。

public int X { get; set; } = x; // C# 6 or higher

他のヒント

2015 年 1 月 2 日に編集

C#6 :

C# 6 では、自動プロパティを直接初期化できます (ついに!)。それを説明する他の回答がスレッドにあります。

C#5以下:

この属性の使用目的は実際にプロパティの値を設定することではありませんが、リフレクションを使用して常にプロパティの値を設定することができます。

public class DefaultValuesTest
{    
    public DefaultValuesTest()
    {               
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
        {
            DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)];

            if (myAttribute != null)
            {
                property.SetValue(this, myAttribute.Value);
            }
        }
    }

    public void DoTest()
    {
        var db = DefaultValueBool;
        var ds = DefaultValueString;
        var di = DefaultValueInt;
    }


    [System.ComponentModel.DefaultValue(true)]
    public bool DefaultValueBool { get; set; }

    [System.ComponentModel.DefaultValue("Good")]
    public string DefaultValueString { get; set; }

    [System.ComponentModel.DefaultValue(27)]
    public int DefaultValueInt { get; set; }
}

変数の初期値をインライン化する場合、それはコンストラクター内で暗黙的に行われます。

この構文は、C# 5 までのベスト プラクティスであったと私は主張します。

class Person 
{
    public Person()
    {
        //do anything before variable assignment

        //assign initial values
        Name = "Default Name";

        //do anything after variable assignment
    }
    public string Name { get; set; }
}

これにより、割り当てられる順序を明確に制御できるようになります。

C#6 以降、新しい方法が追加されました。

public string Name { get; set; } = "Default Name"

DefaultValueAttribute は vs デザイナーでのみ機能します。プロパティをその値に初期化することはありません。

見る DefaultValue 属性が Auto プロパティで機能しない

実際に設定してデータベースに永続化したくない場合は、これを使用することがあります。

class Person
{
    private string _name; 
    public string Name 
    { 
        get 
        {
            return string.IsNullOrEmpty(_name) ? "Default Name" : _name;
        } 

        set { _name = value; } 
    }
}

明らかに、それが文字列でない場合は、オブジェクトを null 可能 (double?、int?) にすることもできます。) そして、それが null であるかどうかを確認し、デフォルトを返すか、設定されている値を返します。

次に、リポジトリをチェックしてそれがデフォルトで永続的ではないかどうかを確認したり、保存する前にバックドア チェックインを行ってバッキング値の実際のステータスを確認したりできます。

お役に立てば幸いです!

C# 6.0 ではこれは簡単です。

で行うことができます Class プロパティ宣言ステートメント内の宣言自体。

public class Coordinate
{ 
    public int X { get; set; } = 34; // get or set auto-property with initializer

    public int Y { get; } = 89;      // read-only auto-property with initializer

    public int Z { get; }            // read-only auto-property with no initializer
                                     // so it has to be initialized from constructor    

    public Coordinate()              // .ctor()
    {
        Z = 42;
    }
}

C# 6.0 以降, 自動実装されたプロパティにデフォルト値を割り当てることができます。

public string Name { get; set; } = "Some Name";

次のような読み取り専用の自動実装プロパティを作成することもできます。

public string Name { get; } = "Some Name";

見る: C#6:最初の反応、自動的に実装されるプロパティのイニシャライザー - Jon Skeet 著

のバージョンで C# (6.0) 以降, 、 できるよ :

読み取り専用プロパティの場合

public int ReadOnlyProp => 2;

書き込み可能プロパティと読み取り可能プロパティの両方の場合

public string PropTest { get; set; } = "test";

現在のバージョンでは C# (7.0), 、 できるよ :(スニペットはむしろ、式本体の get/set アクセサーを使用して、バッキング フィールドを使用するときによりコンパクトにする方法を示しています)

private string label = "Default Value";

// Expression-bodied get / set accessors.
public string Label
{
   get => label;
   set => this.label = value; 
 }

すでに受け入れられている回答に加えて、デフォルトのプロパティを 関数 使用できる他のプロパティの 式本体の表記法 C#6.0 (以降) では、次のようなさらにエレガントで簡潔な構成が可能です。

public class Person{

    public string FullName  => $"{First} {Last}"; // expression body notation

    public string First { get; set; } = "First";
    public string Last { get; set; } = "Last";
}

上記を次のように使用できます

    var p = new Person();

    p.FullName; // First Last

    p.First = "Jon";
    p.Last = "Snow";

    p.FullName; // Jon Snow

上記の「=>」表記を使用できるようにするには、プロパティは読み取り専用である必要があり、get アクセサー キーワードを使用しないでください。

詳細はこちら MSDN

完全なサンプルはほとんどありません:

using System.ComponentModel;

private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
    get { return bShowGroup; }
    set { bShowGroup = value; }
}

私の解決策は、定数またはプロパティ型初期化子を使用してデフォルト値のプロパティ初期化を提供するカスタム属性を使用することです。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InstanceAttribute : Attribute
{
    public bool IsConstructorCall { get; private set; }
    public object[] Values { get; private set; }
    public InstanceAttribute() : this(true) { }
    public InstanceAttribute(object value) : this(false, value) { }
    public InstanceAttribute(bool isConstructorCall, params object[] values)
    {
        IsConstructorCall = isConstructorCall;
        Values = values ?? new object[0];
    }
}

この属性を使用するには、特別な基本クラス初期化子からクラスを継承するか、静的ヘルパー メソッドを使用する必要があります。

public abstract class DefaultValueInitializer
{
    protected DefaultValueInitializer()
    {
        InitializeDefaultValues(this);
    }

    public static void InitializeDefaultValues(object obj)
    {
        var props = from prop in obj.GetType().GetProperties()
                    let attrs = prop.GetCustomAttributes(typeof(InstanceAttribute), false)
                    where attrs.Any()
                    select new { Property = prop, Attr = ((InstanceAttribute)attrs.First()) };
        foreach (var pair in props)
        {
            object value = !pair.Attr.IsConstructorCall && pair.Attr.Values.Length > 0
                            ? pair.Attr.Values[0]
                            : Activator.CreateInstance(pair.Property.PropertyType, pair.Attr.Values);
            pair.Property.SetValue(obj, value, null);
        }
    }
}

使用例:

public class Simple : DefaultValueInitializer
{
    [Instance("StringValue")]
    public string StringValue { get; set; }
    [Instance]
    public List<string> Items { get; set; }
    [Instance(true, 3,4)]
    public Point Point { get; set; }
}

public static void Main(string[] args)
{
    var obj = new Simple
        {
            Items = {"Item1"}
        };
    Console.WriteLine(obj.Items[0]);
    Console.WriteLine(obj.Point);
    Console.WriteLine(obj.StringValue);
}

出力:

Item1
(X=3,Y=4)
StringValue

C# 6 以降では、単純に次の構文を使用できます。

public object Foo { get; set; } = bar;

あることに注意してください。 readonly 次のように、プロパティは単純にセットを省略します。

public object Foo { get; } = bar;

割り当てることもできます readonly コンストラクターからの自動プロパティ。

その前に私は以下のように回答しました。

コンストラクターにデフォルトを追加することは避けたいと思います。それを動的な代入のために残し、変数が代入される 2 つのポイントが存在することを避けます (つまり、型のデフォルトとコンストラクター内)。通常、このような場合は、単純に通常のプロパティを記述します。

もう 1 つのオプションは、ASP.Net と同じことを行い、属性を介してデフォルトを定義することです。

http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx

コンストラクター内。コンストラクターの目的は、データ メンバーを初期化することです。

を使ってみましたか? デフォルト値属性 または ShouldSerialize メソッドと Reset メソッド コンストラクターと連携して?デザイナー画面またはプロパティ グリッドに表示される可能性のあるクラスを作成する場合は、これら 2 つのメソッドのいずれかが必要な気がします。

public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}
private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}

個人的には、自動プロパティ以外に何もするつもりがないのであれば、それをプロパティにする意味がまったくわかりません。そのままフィールドとして残しておきます。これらのアイテムのカプセル化の利点は、それらの背後にカプセル化するものがないため、単なる赤ニシンです。基礎となる実装を変更する必要がある場合でも、依存するコードを壊すことなく、それらをプロパティとして自由にリファクタリングできます。

ふーむ...おそらくこれは後で独自の質問の主題になるでしょう

明確にするために、はい、クラス派生オブジェクトのコンストラクターにデフォルト値を設定する必要があります。コンストラクターが使用される場合、構築に適切なアクセス修飾子を使用して存在することを確認する必要があります。オブジェクトがインスタンス化されていない場合、たとえばコンストラクターはありません (例:静的メソッド)の場合、フィールドによってデフォルト値を設定できます。ここでの理由は、オブジェクト自体は 1 回だけ作成され、インスタンス化はしないということです。

@Darren Kopp - 良い答え、きれいで正しい。繰り返しになりますが、抽象メソッドのコンストラクターを作成できます。コンストラクターを作成するときに、基本クラスからアクセスする必要があるだけです。

基本クラスのコンストラクター:

public BaseClassAbstract()
{
    this.PropertyName = "Default Name";
}

派生/具体/サブクラスのコンストラクター:

public SubClass() : base() { }

ここでのポイントは、基本クラスから抽出されたインスタンス変数によって基本フィールド名が埋もれてしまう可能性があるということです。「this」を使用して現在のインスタンス化されたオブジェクト値を設定します。現在のインスタンスと必要な許可レベル(アクセス修飾子)に関してオブジェクトを正しく形成することができます。

「コンストラクタが終了したらコンストラクタも終了するはず」なのでコンストラクタを使います。プロパティはクラスが保持する状態のようなもので、デフォルトの状態を初期化する必要がある場合は、コンストラクターでそれを行うことになります。

このように単純に置くことができます

    public sealed  class Employee
{
    public int Id { get; set; } = 101;
}
class Person 
{    
    /// Gets/sets a value indicating whether auto 
    /// save of review layer is enabled or not
    [System.ComponentModel.DefaultValue(true)] 
    public bool AutoSaveReviewLayer { get; set; }
}

SomeFlag にデフォルトの false を与えると、これで済むと思います。

private bool _SomeFlagSet = false;
public bool SomeFlag
{
    get
    {
        if (!_SomeFlagSet)
            SomeFlag = false;        

        return SomeFlag;
    }
    set
    {
        if (!_SomeFlagSet)
            _SomeFlagSet = true;

        SomeFlag = value;        
    }
}

インラインで初期化する場合、コンストラクターを使用して初期化するのは悪い習慣であり、後ほど重大な変更が発生する可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top