C# 6 自动属性 ​​- 读取一次还是每次?

C# 6 auto-properties - read once or every time?

我在设置某些属性时遵循一种模式,即检查相应的字段是否为空,如果不是则返回该字段,如果是则设置它。例如,我经常使用它来读取配置设置,以便延迟读取设置并且只读取一次。这是一个例子:

private string DatabaseId
{
    get
    {
        if (string.IsNullOrEmpty(databaseId))
        {
            databaseId = CloudConfigurationManager.GetSetting("database");
        }

        return databaseId;
    }
}

我已经开始使用 C# 6 自动属性初始化,因为它确实清理并使我​​的代码更简洁。我想做这样的事情:

private string DatabaseId { get; } = CloudConfigurationManager.GetSetting("database");

但我不确定编译器在这种情况下如何解释它。这是否与我的第一段代码具有相同的效果,即设置(自动实现的)字段一次,然后从该字段读取?还是每次我得到 DatabaseId 时都会调用 CloudConfigurationManager

auto-属性 自动具有支持字段。在这种情况下,该字段只能从构造函数或 auto-属性 初始化程序中分配。您的新代码比第一个更好。它只会调用一次 CloudConfigurationManager.GetSetting("database");。在第一个示例中,每次调用 属性 get 时都必须进行检查。

它只会设置一次值,然后读取它。

但是,您现在不再拥有 databaseId 字段,这在某种意义上略有不同。在您的第一个示例中,您基本上检查 id == null || id == "" 以设置数据库字符串。这意味着如果您创建一个新实例并将 databaseId 设置为空字符串,第一个示例仍将从设置中获取 ID。

然而,第二个示例会将空字符串视为有效值并保留它。

第一个代码:

if(id == null || id == "") // Get ID from settings

第二个代码:

if(id == null) // Get ID from settings

C# 6.0 readonly auto 属性 将创建一个字段并仅调用一次初始化程序。

但是,这不等于您那里拥有的。在您的代码中,仅当有人阅读 DatabaseId 属性 时才会调用 CloudConfigurationManager.GetSetting,但是 "readonly auto property" CloudConfigurationManager.GetSetting 将在 [=22= 时调用] 初始化本身。

这种差异may/mayn无关紧要。这取决于。如果通话费用昂贵,那么您可以使用 Lazy<T>,这与您拥有的大致相等。

您显示的内容:

private string DatabaseId { get; } = CloudConfigurationManager.GetSetting("database");

是一个 "Auto-Property Initializer",关键字是 "initializer",来自 MSDN Blogs: C# : The New and Improved C# 6.0:

The auto-property initializer allows assignment of properties directly within their declaration. For read-only properties, it takes care of all the ceremony required to ensure the property is immutable.

初始化器运行 每个实例一次(或静态成员每个类型一次)。见 C# Language Specification, 10.4.5 Variable initializers:

For instance fields, variable initializers correspond to assignment statements that are executed when an instance of the class is created.

所以代码编译成这样:

public class ContainingClass
{
    private readonly string _databaseId;
    public string DatabaseId { get { return _databaseId; } }

    public ContainingClass()
    {
        _databaseId = CloudConfigurationManager.GetSetting("database");
    }       
}

对于静态变量,这种看起来是一样的:

private static string DatabaseId { get; } = CloudConfigurationManager.GetSetting("database");

大致编译为:

public class ContainingClass
{
    private static readonly string _databaseId;
    public static string DatabaseId { get { return _databaseId; } }

    static ContainingClass()
    {
        _databaseId = CloudConfigurationManager.GetSetting("database");
    }       
}

虽然不完全,因为当类型没有静态构造函数时,"static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class"。