在最终升级到VS2015并开始使用.NET4.6之后,当我遇到旧课程时,我一直在利用一些语法糖。
不幸的是,这并不总是顺利:/这方面的一个例子是以下示例。
我现有的代码可以使用。
private static string _bootstrapBundle;
public static string BootstrapBundle
{
get
{
return _bootstrapBundle;
}
}
使用表达式主体的快速重写给了我这个,它起作用
private static string _bootstrapBundle;
public static string BootstrapBundle => _bootstrapBundle;
这也可以重写为使用自动属性,如下面的代码
public static string BootstrapBundle { get; private set; }
如果我尝试更进一步,并写下以下内容,它就不起作用
private static string _bootstrapBundle;
public static string BootstrapBundle { get; private set; } = _bootstrapBundle;
所有三个代码示例都编译得很好,但是当我稍后尝试分配如下所示的值时,它只能使用最后一段代码而无法将任何内容分配给BootstrapBundle。
BootstrapBundle = SquishIt.Framework.Bundle.Css()
.Add("/assets/stylesheets/Theme/" + theme + "/Bootstrap/bootstrap.less")
.Render("/assets/Cache/bootstrap.css");
这怎么可能?表达式是否以不同方式解析在不同的时间?我在滥用语法吗?
答案 0 :(得分:4)
让我们逐一了解你给出的选项,看看每个选项:
private static string _bootstrapBundle;
public static string BootstrapBundle
{
get
{
return _bootstrapBundle;
}
}
我假设我不必解释这是做什么的。但请注意,如果您尝试分配给BootstrapBundle
,它将在编译时失败,因为没有setter。但是你可以通过直接分配到该领域来解决这个问题。
private static string _bootstrapBundle;
public static string BootstrapBundle => _bootstrapBundle;
这与#1完全相同,只是语法更简洁。
public static string BootstrapBundle { get; private set; }
这里我们有一个auto-property,这是一个隐藏(不可言说的)后备字段的属性。它汇编为:
private static string <BootstrapBundle>k__BackingField;
public static string BootstrapBundle
{
get
{
return <BootstrapBundle>k__BackingField;
}
private set
{
<BootstrapBundle>k__BackingField = value;
}
}
这意味着现在设置属性并在设置后获取它将为您提供新值。
private static string _bootstrapBundle;
public static string BootstrapBundle { get; private set; } = _bootstrapBundle;
这与#3相同,只是隐藏的支持字段被初始化为您给出的值:
private static string _bootstrapBundle;
private static string <BootstrapBundle>k__BackingField = _bootstrapBundle;
public static string BootstrapBundle
{
get
{
return <BootstrapBundle>k__BackingField;
}
private set
{
<BootstrapBundle>k__BackingField = value;
}
}
这意味着现在有两个字段:一个隐藏,一个隐藏。隐藏字段最初将设置为可见字段的值(null
),但在此之后,这两个字段不会相互影响。
这意味着如果您设置属性,然后获取属性,您将获得更新的值。但是,如果您阅读可见字段,则其值不会更新。反之亦然:如果您更新字段,则属性的值不会更改。
答案 1 :(得分:2)
如果您希望行为完全相同,则可以使用以下两个选项:
有了体验(就像你提供的那样,并且不需要其他重构):
private static string _bootstrapBundle;
public static string BootstrapBundle => _bootstrapBundle;
使用自动属性(就像你也建议的那样,你必须重构所有赋值以使用属性而不是字段变量):
public static string BootstrapBundle { get; private set; }
你的上一个例子不起作用的原因是,当你尝试分配字段变量时,字段变量没有值,在使用表达式主体时,每次访问属性时都会解析getter,并且赋值可以被推迟。换句话说,它只是作为readonly工作,并且变量的赋值必须在构造函数内部发生,使得字段变量无用,除非你想将它用于其他方法(这将是完全不可读的和糟糕的调试经验!) :)
如果您希望上一个示例有效,则必须使用常量:
public static string BootstrapBundle { get; private set; } = "42";
但是如果您不需要默认值,那么您也不需要进行太多更改,您也可以将其删除。
答案 2 :(得分:0)
有几种方法可以定义属性:
// this defines a public getter, public setter property with no backing field (there is an internal one, but not one you can access)
public static string BootstrapBundle {
get;
set;
}
// this defines a public getter, public setter property with a backing field
private static string _bootstrapBundle = "42";
public static string BootstrapBundle {
get {
return _bootstrapBundle;
}
set {
_bootstrapBundle = value;
}
}
//this defines a no setter property with a backing field
private static string _bootstrapBundle = "42";
public static string BootstrapBundle {
get {
return _bootstrapBundle;
}
}
使用C#6功能:
// this sets a getter only property that returns the current value of _bootstrapBundle (equivalent to the last form in the code above)
private static string _bootstrapBundle = "42";
public static string BootstrapBundle => _bootstrapBundle;
// this sets up an auto property (no backing field) that at initialization gets the initial value of _bootstrapBundle
private static string _bootstrapBundle = "42";
public static string BootstrapBundle {get;set;} = _bootstrapBundle;
// equivalent to this:
public static string BootstrapBundle {get;set;} = "42";
由于您在代码中设置了属性,这意味着您需要一个setter。如果您想要的只是具有支持字段的属性,那么您没有C#6语法来替换旧的return _backingField;/_backingField=value