2177

C# の自動プロパティに初期値を与えるにはどうすればよいですか?

コンストラクターを使用するか、古い構文に戻します。

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

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

通常のプロパティ構文の使用 (初期値あり)

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

より良い方法はありますか?

4

23 に答える 23

2767

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

C# 6.0 から、インラインで初期値を指定できるようになりました。構文は次のとおりです。

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

DefaultValueAttribute初期値ではなく、デフォルト値を指定するために VS デザイナー (またはその他の消費者) によって使用されることを意図しています。(設計対象であっても、初期値はデフォルト値です)。

コンパイル時DefaultValueAttributeには、生成された IL に影響を与えず、プロパティをその値に初期化するために読み込まれません ( DefaultValue 属性が Auto プロパティで機能しないを参照してください)。

IL に影響を与える属性の例はThreadStaticAttribute、、、CallerMemberNameAttribute...

于 2008-09-02T21:46:23.683 に答える
321

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; }
}
于 2011-06-22T18:14:58.580 に答える
198

変数の初期値をインライン化すると、とにかくコンストラクターで暗黙的に実行されます。

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

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";
于 2008-09-04T12:16:06.860 に答える
68

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

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

        set { _name = value; } 
    }
}

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

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

それが役立つことを願っています!

于 2008-09-02T23:07:27.560 に答える
44

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

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

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

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

参照: C# 6: 最初の反応、自動的に実装されるプロパティの初期化子 - Jon Skeet 著

于 2014-04-29T14:40:19.983 に答える
35

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; 
 }
于 2017-03-15T01:07:28.783 に答える
23

すでに受け入れられている回答に加えて、デフォルトのプロパティを他のプロパティの関数として定義するシナリオでは、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で

于 2016-10-30T02:16:41.230 に答える
18

C# 9.0では、キーワードのサポートが追加されました。これは、読み取り専用の自動プロパティを宣言するための非常に便利で非常に洗練された方法です。init

宣言する:

class Person 
{ 
    public string Name { get; init; } = "Anonymous user";
}

〜お楽しみください〜

// 1. Person with default name
var anonymous = new Person();
Console.WriteLine($"Hello, {anonymous.Name}!");
// > Hello, Anonymous user!


// 2. Person with assigned value
var me = new Person { Name = "@codez0mb1e"};
Console.WriteLine($"Hello, {me.Name}!");
// > Hello, @codez0mb1e!


// 3. Attempt to re-assignment Name
me.Name = "My fake"; 
// > Compilation error: Init-only property can only be assigned in an object initializer
于 2021-05-24T14:13:58.850 に答える
14

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

于 2008-09-04T17:08:08.763 に答える
13

少し完全なサンプル:

using System.ComponentModel;

private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
    get { return bShowGroup; }
    set { bShowGroup = value; }
}
于 2010-06-17T07:44:02.513 に答える
12

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

[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
于 2013-01-17T22:04:13.313 に答える
7

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

于 2016-07-18T16:39:49.720 に答える
5

コンストラクターと組み合わせて、 DefaultValueAttributeまたはShouldSerialize および Reset メソッドを使用してみましたか? デザイナー サーフェイスまたはプロパティ グリッドに表示される可能性のあるクラスを作成する場合は、これら 2 つのメソッドのいずれかが必要だと思います。

于 2008-09-02T21:32:41.657 に答える
4

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

于 2016-01-11T11:33:09.490 に答える
3

これは今では古く、私の立場は変わりました。私は後世のために元の答えを残しています。


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

うーん...多分これは後でそれ自身の質問の主題になるでしょう

于 2008-09-03T03:43:20.533 に答える
3

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

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

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

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

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

public SubClass() : base() { }

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

于 2012-07-31T11:02:41.160 に答える
3
public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}
于 2014-09-04T20:44:06.380 に答える
1
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; }
}
于 2011-05-26T19:29:05.667 に答える
-3

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

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

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

        SomeFlag = value;        
    }
}
于 2013-12-06T21:50:59.703 に答える