【问题标题】:C# 6 auto-properties - read once or every time?C# 6 自动属性 ​​- 读取一次还是每次读取?
【发布时间】:2015-08-17 13:43:20
【问题描述】:

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

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

【问题讨论】:

  • 是的,它是一个初始化器,以避免所有代码
  • @Ivan 尝试将对CloudConfigurationManager.GetSetting("database") 的调用包装在另一个函数中,在其上放置一个断点,并查看它是否被多次调用。

标签: c# automatic-properties c#-6.0


【解决方案1】:

你展示了什么:

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

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

自动属性初始化器允许直接在其声明中分配属性。对于只读属性,它负责确保属性不可变所需的所有仪式。

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

对于实例字段,变量初始值设定项对应于在创建类的实例时执行的赋值语句。

所以代码编译成这样的:

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");
    }       
}

虽然不完全是,当类型没有静态构造函数时,“静态字段初始化器在第一次使用该类的静态字段之前在依赖于实现的时间执行”。

【讨论】:

    【解决方案2】:

    C# 6.0 只读自动属性将创建一个字段并仅调用一次初始化程序。

    但是,这不等于您在那里拥有的东西。在您的代码中,CloudConfigurationManager.GetSetting 仅在有人读取 DatabaseId 属性时才会被调用,但在类初始化本身时将调用“只读自动属性”CloudConfigurationManager.GetSetting

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

    【讨论】:

      【解决方案3】:

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

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

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

      第一个代码:

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

      第二个代码:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多