编译错误。在struct中使用属性

时间:2010-12-02 14:00:01

标签: c# struct compiler-errors language-features

请在struct构造函数中解释以下错误。如果我将struct更改为class 错误消失了。

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

    public DealImportRequest(DealRequestBase drb)
    {
        DealReq = drb;
        ImportRetryCounter = 0;
    }
}
  • 错误CS0188:在将所有字段分配给
  • 之前,不能使用'this'对象
  • 错误CS0843:自动实现的属性的备份字段 在将控制权返回给调用者之前,必须完全分配“DealImportRequest.DealReq”。考虑从构造函数初始化程序中调用默认构造函数。

3 个答案:

答案 0 :(得分:14)

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

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

来自语言规范:

  

10.7.3自动实施的属性

     

当财产是   自动指定   实施财产,隐藏的支持   字段自动可用   财产,以及访问者   实现读取和写入   支持领域。 [...]因为   支持领域是不可访问的,它可以   只能通过阅读和书写   财产访问者,甚至在   包含类型。 [...] 这个   限制也意味着明确   使用。分配结构类型   自动实现的属性只能   使用标准实现   结构的构造函数,因为   分配给房产本身   要求结构是明确的   分配。这意味着用户定义   构造函数必须调用默认值   构造

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

请注意,您在那里的结构是可变的。 This is not recommended。我建议您将类型设为类(您的编译问题应立即消失)或使类型不可变。最简单的方法是,假设你提供的代码是整个结构,将使setter私有化(get; private set;)。当然,您还应该确保在之后依赖私有访问来修改字段的结构中不添加任何变异方法。或者,您可以使用readonly支持字段支持属性,并完全删除setter。

答案 1 :(得分: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提供默认的无参数构造函数。
  4. 前两个是可选的(如果你愿意,你可以明确地写它们)但第三个不是 - 我们不允许为struct的无参数构造函数编写自己的代码,我们必须去一个像上面代码中的那个一样自动给我们。

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

    这是我们通常无需考虑的不同自动功能的组合,但在这种情况下效果不佳。我们可以通过遵循843的错误消息中的建议并将默认构造函数作为显式构造函数的一部分来解决此问题:

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

    考虑到上述代码的扩展版本,你可以看到它如何解决这个问题,因为它调用了构造函数,在它继续之前分配给支持字段。

答案 2 :(得分:0)

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