提问人:bentford 提问时间:9/3/2008 最后编辑:LopDevbentford 更新时间:7/5/2023 访问量:1235627
为 C# 自动属性提供初始值的最佳方法是什么?
What is the best way to give a C# auto-property an initial value?
问:
如何为 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;
}
}
有没有更好的方法?
答:
您是否尝试过将 DefaultValueAttribute 或 ShouldSerialize 和 Reset 方法与构造函数结合使用?我觉得如果你正在制作一个可能显示在设计器图面或属性网格中的类,这两种方法之一是必要的。
在 C# 5 及更早版本中,若要为自动实现的属性提供初始值,必须在构造函数中执行此操作。
从 C# 6.0 开始,可以内联指定初始值。语法为:
public int X { get; set; } = x; // C# 6 or higher
DefaultValueAttribute
旨在由 VS 设计器(或任何其他使用者)用于指定默认值,而不是初始值。(即使在设计对象中,初始值也是默认值)。
在编译时不会影响生成的 IL,并且不会读取它以将属性初始化为该值(请参阅 DefaultValue 属性不适用于我的自动属性)。DefaultValueAttribute
影响 IL 的属性示例包括 ThreadStaticAttribute
、CallerMemberNameAttribute
、...
评论
public int X { get; } = x;
x
x
x
有时我使用它,如果我不想让它实际设置并持久化在我的数据库中:
class Person
{
private string _name;
public string Name
{
get
{
return string.IsNullOrEmpty(_name) ? "Default Name" : _name;
}
set { _name = value; }
}
}
显然,如果它不是字符串,那么我可能会使对象可为 null( double?, int? ) 并检查它是否为 null,返回默认值或返回它设置为的值。
然后,我可以检查我的存储库,看看它是否是我的默认值并且不持久化,或者在保存之前进行后门检查以查看后备值的真实状态。
评论
return _name ?? "Default Name";
甚至可能更清楚你的
这已经很老了,我的立场也变了。我把原来的答案留给后代。
就个人而言,如果您不打算在自动属性之外做任何事情,我认为将其作为属性根本没有意义。只需将其保留为字段即可。这些项目的封装好处只是红鲱鱼,因为它们背后没有任何东西可以封装。如果需要更改底层实现,您仍然可以自由地将它们重构为属性,而不会破坏任何依赖代码。
嗯。。。也许这将是它以后自己问题的主题
评论
当您内联变量的初始值时,无论如何都会在构造函数中隐式完成。
我认为这种语法是 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";
在 C# 6 及更高版本中,您可以简单地使用以下语法:
public object Foo { get; set; } = bar;
请注意,要使属性省略该集,如下所示:readonly
public object Foo { get; } = bar;
您还可以从构造函数中分配自动属性。readonly
在此之前,我的回复如下。
我会避免向构造函数添加默认值;将其留给动态赋值,并避免在赋值变量的两个点(即类型默认值和构造函数中)。通常,在这种情况下,我会简单地编写一个普通属性。
另一种选择是执行 ASP.Net 执行的操作,并通过属性定义默认值:
http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx
评论
小完整示例:
using System.ComponentModel;
private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
get { return bShowGroup; }
set { bShowGroup = value; }
}
评论
DefaultValueAttribute
ShowGroup
true
false
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; }
}
评论
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; }
}
评论
澄清一下,是的,您需要在类派生对象的构造函数中设置默认值。您需要确保构造函数存在,并在使用时具有正确的构造访问修饰符。如果对象没有实例化,例如它没有构造函数(例如静态方法),则可以通过字段设置默认值。这里的理由是,对象本身只会创建一次,并且您不会实例化它。
@Darren Kopp - 好答案,干净,正确。重申一下,您可以为 Abstract 方法编写构造函数。在编写构造函数时,您只需要从基类访问它们:
基类的构造函数:
public BaseClassAbstract()
{
this.PropertyName = "Default Name";
}
派生/具体/子类的构造函数:
public SubClass() : base() { }
这里的要点是,从基类中提取的实例变量可能会隐藏您的基字段名称。使用“this.”设置当前实例化的对象值将允许您根据当前实例和实例化对象所需的权限级别(访问修饰符)正确形成对象。
我的解决方案是使用自定义属性,该属性通过常量或使用属性类型初始值设定项提供默认值属性初始化。
[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
评论
我认为这会为你提供 SomeFlag 默认值 false。
private bool _SomeFlagSet = false;
public bool SomeFlag
{
get
{
if (!_SomeFlagSet)
SomeFlag = false;
return SomeFlag;
}
set
{
if (!_SomeFlagSet)
_SomeFlagSet = true;
SomeFlag = value;
}
}
从 C# 6.0 开始,我们可以为自动实现的属性分配默认值。
public string Name { get; set; } = "Some Name";
我们还可以创建只读自动实现的属性,例如:
public string Name { get; } = "Some Name";
请参见: C# 6:自动实现属性的第一反应、初始值设定项 - 作者:Jon Skeet
public Class ClassName{
public int PropName{get;set;}
public ClassName{
PropName=0; //Default Value
}
}
评论
使用构造函数,因为“构造函数完成后,构造应该完成”。属性就像你的类所持有的状态,如果你必须初始化一个默认状态,你可以在你的构造函数中这样做。
在构造函数中。构造函数的目的是初始化其数据成员。
在 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;
}
}
评论
{ get; set; }
{ get; private set; }
除了已接受的答案之外,对于要将默认属性定义为其他属性的函数的方案,可以在 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 上的详细信息
评论
FullName
是一个没有后备字段的计算属性,因此这并不能真正回答关于汽车属性的问题。
在 C# (6.0) 及更高版本中,您可以执行以下操作:
对于 Readonly 属性
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;
}
评论
class C { public DateTime P { get; } = DateTime.Now; public DateTime Q => DateTime.Now; }
P
Q
P
Q
private string name;
public string Name
{
get
{
if(name == null)
{
name = "Default Name";
}
return name;
}
set
{
name = value;
}
}
评论
get;
set;
get
你可以简单地这样说
public sealed class Employee
{
public int Id { get; set; } = 101;
}
我知道这是一个老问题,但是当我在寻找如何通过覆盖选项继承默认值时,它出现了,我想出了
//base class
public class Car
{
public virtual string FuelUnits
{
get { return "gasoline in gallons"; }
protected set { }
}
}
//derived
public class Tesla : Car
{
public override string FuelUnits => "ampere hour";
}
评论
在 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
评论
public string Name { get; } = "Anonymous user";
评论