繁体   English   中英

表达式绑定功能与自动属性结合会导致问题

[英]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");

怎么会这样? 表达式的解析方式是否不同? 在不同的时间? 我在滥用语法吗?

让我们逐个介绍一下这些选项,然后看看每个选项的作用:

  1.  private static string _bootstrapBundle; public static string BootstrapBundle { get { return _bootstrapBundle; } } 

    我假设我不必解释这是什么。 但是请注意,如果您尝试分配给BootstrapBundle ,由于没有设置器,它将在编译时失败。 但是您可以通过直接分配给该字段来解决此问题。

  2.  private static string _bootstrapBundle; public static string BootstrapBundle => _bootstrapBundle; 

    这与#1完全相同,只是语法更简洁。

  3.  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; } } 

    这意味着现在可以设置属性,并且在设置后获取该属性将为您提供新的值。

  4.  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. 使用expession主体(如您提供的那样,并且不需要其他重构):

     private static string _bootstrapBundle; public static string BootstrapBundle => _bootstrapBundle; 
  2. 使用自动属性(如您还建议的那样,在这里您必须重构所有分配以使用属性而不是字段变量):

     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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM