Expression-Bodied 函数与自动属性结合导致问题
Expression-Bodied Function combined with Auto Properties results in problems
在最终升级到 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");
怎么会这样?表达式的解析方式不同吗?在不同的时间?我在滥用语法吗?
有几种定义属性的方法:
// 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
如果您希望行为完全相同,您有以下两种选择:
具有表达式主体(就像您提供的那样,并且不需要其他重构):
private static string _bootstrapBundle;
public static string BootstrapBundle => _bootstrapBundle;
使用自动属性(就像你也建议的那样,在这里你必须重构所有赋值以使用 属性 而不是字段变量):
public static string BootstrapBundle { get; private set; }
上一个示例不起作用的原因是,当您尝试分配字段变量时它没有值,因为使用表达式正文,每次访问时都会解析 getter 属性,赋值可以延迟。换句话说,它以只读方式工作,并且变量的赋值必须在构造函数内部发生,从而使字段变量无用,除非您想将它用于其他方法(这将是完全不可读的并且调试体验很糟糕!) :)
如果你想让你的最后一个例子起作用,你必须改用常量:
public static string BootstrapBundle { get; private set; } = "42";
但如果您不需要默认值,则无需进行太多更改,您也可以将其保留。
让我们逐一浏览您给出的选项,看看每个选项的作用:
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-属性,这是一个 属性 带有隐藏的(不可描述的)支持字段。它编译为:
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
),但之后,两个字段将不会相互影响。
这意味着如果您设置属性,然后获取属性,您将获得更新后的值。但是如果你读取可见字段,它的值将不会被更新。反之亦然:如果您更新字段,属性 的值不会改变。
在最终升级到 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");
怎么会这样?表达式的解析方式不同吗?在不同的时间?我在滥用语法吗?
有几种定义属性的方法:
// 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
如果您希望行为完全相同,您有以下两种选择:
具有表达式主体(就像您提供的那样,并且不需要其他重构):
private static string _bootstrapBundle; public static string BootstrapBundle => _bootstrapBundle;
使用自动属性(就像你也建议的那样,在这里你必须重构所有赋值以使用 属性 而不是字段变量):
public static string BootstrapBundle { get; private set; }
上一个示例不起作用的原因是,当您尝试分配字段变量时它没有值,因为使用表达式正文,每次访问时都会解析 getter 属性,赋值可以延迟。换句话说,它以只读方式工作,并且变量的赋值必须在构造函数内部发生,从而使字段变量无用,除非您想将它用于其他方法(这将是完全不可读的并且调试体验很糟糕!) :)
如果你想让你的最后一个例子起作用,你必须改用常量:
public static string BootstrapBundle { get; private set; } = "42";
但如果您不需要默认值,则无需进行太多更改,您也可以将其保留。
让我们逐一浏览您给出的选项,看看每个选项的作用:
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-属性,这是一个 属性 带有隐藏的(不可描述的)支持字段。它编译为:
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
),但之后,两个字段将不会相互影响。这意味着如果您设置属性,然后获取属性,您将获得更新后的值。但是如果你读取可见字段,它的值将不会被更新。反之亦然:如果您更新字段,属性 的值不会改变。