首页 文章

如何为C#Auto-Property提供默认值?

提问于
浏览
1529

如何为C#Auto-Property提供默认值?我要么使用构造函数,要么还原为旧语法 .

Using the Constructor:

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

Using normal property syntax (使用默认值)

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

有没有更好的办法?

22 回答

  • 0

    有时我会使用它,如果我不希望它实际设置并持久保存在我的数据库中:

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

    显然,如果它不是字符串,那么我可以使对象可以为空(double?,int?)并检查它是否为null,返回默认值,或返回它设置的值 .

    然后,我可以在我的存储库中检查它是否是我的默认值而不是持久性,或者在保存之前检查后门是否检查支持值的真实状态 .

    希望有所帮助!

  • 9

    就个人而言,如果你不打算在汽车 property 之外做任何事情,我根本就没有把它变成 property 的意义 . 把它留作田地吧 . 这些项目的封装优势只是红色鲱鱼,因为它们背后没有什么可以封装的 . 如果您需要更改底层实现,您仍然可以自由地将它们重构为属性而不会破坏任何相关代码 .

    嗯...也许这将成为后来问题的主题

  • 1750

    使用构造函数,因为“当构造函数完成时,应该完成构造” . 属性就像您的类所持有的状态,如果必须初始化默认状态,则可以在构造函数中执行此操作 .

  • 2

    我认为这样做会让你的SomeFlag默认为false .

    private bool _SomeFlagSet = false;
    public bool SomeFlag
    {
        get
        {
            if (!_SomeFlagSet)
                SomeFlag = false;        
    
            return SomeFlag;
        }
        set
        {
            if (!_SomeFlagSet)
                _SomeFlagSet = true;
    
            SomeFlag = value;        
        }
    }
    
  • 16

    在C#(6.0)及更高版本中,您可以:

    For Readonly properties

    public int ReadOnlyProp => 2;
    

    For both Writable & Readable properties

    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; 
     }
    
  • 74

    小完整样本:

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

    除了已经接受的答案之外,对于您希望将默认属性定义为其他属性的函数的场景,您可以在C#6.0(及更高版本)上使用 expression body notation 来获得更优雅和简洁的结构,例如:

    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 accessor关键字 .

    有关MSDN的详细信息

  • 1

    当你为变量内联一个初始值时,无论如何都会在构造函数中隐式地完成它 .

    我认为这种语法是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"
    
  • 1

    在C#6及更高版本中,您只需使用以下语法:

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

    请注意,要使 readonly 属性只是省略该集合,如下所示:

    public object Foo { get; } = bar;
    

    您还可以从构造函数中分配 readonly auto-properties .

    在此之前,我回答如下 .

    我会避免在构造函数中添加默认值;留下动态赋值,避免分配变量的两个点(即默认类型和构造函数) . 通常我只是在这种情况下写一个普通的属性 .

    另一个选择是执行ASP.Net所做的事情并通过属性定义默认值:

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

  • -2

    DefaultValueAttribute仅适用于vs设计器 . 它不会将属性初始化为该值 .

    DefaultValue attribute is not working with my Auto Property

  • 2

    在C#5和更早版本中,要为自动实现的属性提供默认值,您必须在构造函数中执行此操作 .

    自C#6.0以来,包含自动属性初始化程序的能力 . 语法是:

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

    在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;
        }
    }
    
  • 1

    我的解决方案是使用自定义属性,该属性通过常量或使用属性类型初始化程序提供默认值属性初始化 .

    [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
    
  • 7

    Starting with C# 6.0 ,我们可以为自动实现的属性分配默认值 .

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

    我们还可以创建只读的自动实现属性,如:

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

    见:C# 6: First reactions , Initializers for automatically implemented properties - By Jon Skeet

  • 1

    为了澄清,是的,您需要在类派生对象的构造函数中设置默认值 . 您需要确保构造函数具有适当的访问修饰符,以便在使用时进行构造 . 如果对象未被实例化,例如它没有构造函数(例如静态方法),然后可以通过字段设置默认值 . 这里的原因是对象本身只会创建一次而你不会实例化它 .

    @Darren Kopp - 很好的答案,干净,正确 . 重申一下,您可以编写Abstract方法的构造函数 . 在编写构造函数时,您只需要从基类访问它们:

    基类的构造函数:

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

    派生/混凝土/子类的构造函数:

    public SubClass() : base() { }
    

    这里的要点是从基类中提取的实例变量可能会掩埋您的基本字段名称 . 使用“this”设置当前实例化的对象值 . 将允许您根据当前实例和所需的权限级别正确地形成对象(访问修饰符)您要实例化它 .

  • 4
    private string name;
    public string Name 
    {
        get 
        {
            if(name == null)
            {
                name = "Default Name";
            }
            return name;
        }
        set
        {
            name = value;
        }
    }
    
  • -5
    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; }
    }
    
  • 22
    public Class ClassName{
        public int PropName{get;set;}
        public ClassName{
            PropName=0;  //Default Value
        }
    }
    
  • 10

    在行中初始化,使用构造函数进行初始化是不好的做法,以后会导致更多的破坏性更改 .

  • 252

    在构造函数中 . 构造函数的目的是初始化它的数据成员 .

  • 134

    您是否尝试将DefaultValueAttributeShouldSerialize and Reset methods与构造函数一起使用?如果您正在创建一个可能出现在设计器表面或属性网格中的类,我觉得这两种方法中的一种是必要的 .

  • 30

    编辑1/2/15

    使用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; }
    }
    

相关问题