2010-12-02 87 views
10

请解释结构构造函数的以下错误。如果我将结构更改为类 ,则错误消失。编译错误。使用属性struct

public struct DealImportRequest 
{ 
    public DealRequestBase DealReq { get; set; } 
    public int ImportRetryCounter { get; set; } 

    public DealImportRequest(DealRequestBase drb) 
    { 
     DealReq = drb; 
     ImportRetryCounter = 0; 
    } 
} 
  • 错误CS0188:之前所有的字段被分配到
  • 错误CS0843的“这个”对象不能使用:支持字段的自动实现的属性 “DealImportRequest.DealReq”必须完全分配在控制返回给调用者之前。考虑从构造函数初始值设定项中调用默认构造函数。
+0

可能的重复http://stackoverflow.com/questions/2534960/c-struct-constructor-fields-must-be-fully-assigned-before-control-is-returned – Hps 2010-12-02 14:02:59

+0

@HPS,我不同意。虽然它涉及到与该问题相同的问题,但它与隐式字段相比(支持自动属性)而不是明确字段的事实足以阻止某人看到这两个问题相关的原因。这应该足以认为他们不是重复IMO。 – 2010-12-02 14:29:55

回答

14

由于错误消息的建议,您可以通过从构造函数初始值设定项中调用默认构造函数来解决此问题。

public DealImportRequest(DealRequestBase drb) : this() 
{ 
    DealReq = drb; 
    ImportRetryCounter = 0; 
} 

从语言规范:

10.7.3自动实现的属性

当属性被 指定为自动 实现的属性,一个隐藏的背衬 字段是自动可用于 的财产,并访问器是 实施读取并写入 支持领域。 [...]由于 后台字段不可访问,因此只能通过 属性访问器读取和写入 ,即使在 包含类型中也是如此。 [...] 这 限制也意味着, 自动实现的属性明确 分配结构类型只能 使用标准的 构造的结构,因为 分配给物业本身 实现,需要的结构来绝对是 分配。这意味着用户定义的 构造函数必须调用默认的构造函数 。

另一个(更详细的)替代方法当然是手动实现属性并在构造函数中自行设置支持字段。

请注意你在那里的结构是可变的。 This is not recommended。我建议你或者让类型成为一个类(你的编译问题应该马上消失),或者使类型不可变。假设您提供的代码是整个结构,最简单的方法就是使setter成为私有的(get; private set;)。当然,你也应该确保你不会在结构中添加任何依赖私有访问修改字段的变异方法。或者,您可以使用readonly支持字段替换属性,并完全摆脱setters。

3

你的代码等同于以下代码:

public struct DealImportRequest 
{ 
    private DealRequestBase _dr; 
    private int _irc; 
    public DealRequestBase DealReq 
    { 
     get { return _dr; } 
     set { _dr = value; } 
    } 
    public int ImportRetryCounter 
    { 
     get { return _irc; } 
     set { _irc = value; } 
    } 
    /* Note we aren't allowed to do this explicitly - this is didactic code only and isn't allowed for real*/ 
    public DealImportRequest() 
    { 
     this._dr = default(DealRequestBase); // i.e. null or default depending on whether this is reference or value type. 
     this._irc = default(int); // i.e. 0 
    } 
    public DealImportRequest(DealRequestBase drb) 
    { 
     this.DealReq = drb; 
     this.ImportRetryCounter = 0; 
    } 
} 

现在,所有我在这里所做的是删除语法糖是:

  1. 实现自动属性。
  2. 计算出哪些成员处理相对于this
  3. 提供所有struct s默认无参数构造函数。

前两个是可选的(你可以明确他们写,如果你愿意),但第三个是不是 - 我们不允许我们自己写的代码为struct的参数的构造函数,我们一起去一个像上面代码中那样工作的工具会自动提供给我们。

现在,看看这里,突然两个错误的含义变得清晰了 - 您的构造函数在分配字段(错误188)之前隐式使用this,而那些字段是支持自动属性(错误843)的字段。

这是不同自动功能的组合,通常我们不必考虑,但在这种情况下效果不佳。我们可以通过下面的在843错误信息的建议,并调用默认的构造函数的显式构造的一部分,解决这个问题:

public DealImportRequest(DealRequestBase drb) 
    :this() 
{ 
    DealReq = drb; 
    ImportRetryCounter = 0; 
} 

关于我的扩展上面代码的版本考虑到这一点,你可以看到这解决了这个问题,因为它会在继续进行之前调用分配给后台字段的构造函数。

0

我会建议不要使用自动属性的结构,除非你有充分的理由使用它们。在读写属性中包装类字段非常有用,因为它使得实例可以控制可以读取或写入的环境,并在发生读取或写入时采取行动。此外,对象实例中的代码可以识别正在执行的实例,并且因此可以仅在读取和写入特定实例时才执行特殊操作。在类的早期版本中使用自动属性将使未来版本的类可以使用包含上述优点的手动实现的属性,同时保留与已编译的客户端代码的兼容性。不幸的是,将一个struct字段封装在一个读写属性中并不能提供这些好处,因为一个结构实例的字段可以被复制到另一个结构中,而没有任何实例在这个问题上有任何发言权。如果一个结构的语义允许在大多数情况下使用任意值来编写一个属性[就像自动属性一样],那么任何合法的替换在语义上都等价于一个字段。