[英]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");
怎么会这样? 表达式的解析方式是否不同? 在不同的时间? 我在滥用语法吗?
让我们逐个介绍一下这些选项,然后看看每个选项的作用:
private static string _bootstrapBundle; public static string BootstrapBundle { get { return _bootstrapBundle; } }
我假设我不必解释这是什么。 但是请注意,如果您尝试分配给BootstrapBundle
,由于没有设置器,它将在编译时失败。 但是您可以通过直接分配给该字段来解决此问题。
private static string _bootstrapBundle; public static string BootstrapBundle => _bootstrapBundle;
这与#1完全相同,只是语法更简洁。
public static string BootstrapBundle { get; private set; }
在这里,我们有一个自动属性,它是具有隐藏(无法说)后备字段的属性。 它编译为:
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
),但是此后,这两个字段将不会相互影响。
这意味着,如果您设置属性,然后获取该属性,则将获取更新后的值。 但是,如果您阅读可见字段,则其值将不会更新。 反之亦然:如果更新该字段,则该属性的值不会更改。
如果希望行为完全相同,则有以下两个选择:
使用expession主体(如您提供的那样,并且不需要其他重构):
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";
但是,如果您不需要默认值,则不需要太多更改,因此最好将其省略。
有几种定义属性的方法:
// 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.