编译错误。将属性与结构一起使用

发布于 2024-10-05 10:35:55 字数 480 浏览 7 评论 0原文

请解释以下有关结构构造函数的错误。如果我将结构更改为类 错误消失了。

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”。考虑从构造函数初始值设定项调用默认构造函数。

Please explain the following error on struct constructor. If i change struct to class
the erros are gone.

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

    public DealImportRequest(DealRequestBase drb)
    {
        DealReq = drb;
        ImportRetryCounter = 0;
    }
}
  • error CS0188: The 'this' object cannot be used before all of its fields are assigned to
  • error CS0843: Backing field for automatically implemented property
    'DealImportRequest.DealReq' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半岛未凉 2024-10-12 10:35:55

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

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

从语言规范来看:

10.7.3 自动实现的属性

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

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

请注意,您拥有的结构是可变的。 不建议这样做。我建议您要么将类型设置为类(您的编译问题应该立即消失),要么将类型设置为不可变。实现此目的的最简单方法是假设您提供的代码是整个结构,则将设置器设置为私有(get; private set;)。当然,您还应该确保之后不会向结构添加任何依赖私有访问来修改字段的变异方法。或者,您可以使用 readonly 支持字段来支持属性,并完全删除 setter。

As the error message recommends, you can resolve this by calling the default constructor from a constructor initializer.

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

From the language specification:

10.7.3 Automatically implemented properties

When a property is
specified as an automatically
implemented property, a hidden backing
field is automatically available for
the property, and the accessors are
implemented to read from and write to
that backing field. [...] Because the
backing field is inaccessible, it can
be read and written only through the
property accessors, even within the
containing type. [...] This
restriction also means that definite
assignment of struct types with
auto-implemented properties can only
be achieved using the standard
constructor of the struct, since
assigning to the property itself
requires the struct to be definitely
assigned. This means that user-defined
constructors must call the default
constructor.

The other (more verbose) alternative, of course, is to manually implement the properties and set the backing fields yourself in the constructor.

Do note that the struct you have there is mutable. This is not recommended. I suggest you either make the type a class (your compilation problems should go away immediately) or make the type immutable. The easiest way to accomplish this, assuming the code you have presented is the entire struct, would be to make the setters private (get; private set;). Of course, you should also make sure that you don't add any mutating methods to the struct afterwards that rely on private access to modify the fields. Alternatively, you could back the properties with readonly backing fields and get rid of the setters altogether.

韵柒 2024-10-12 10:35:55

您拥有的代码相当于以下代码:

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提供默认的无参数构造函数。

前两个是可选的(如果您愿意,您可以显式地编写它们),但第三个不是 - 我们不允许为 struct 的无参数构造函数编写自己的代码,我们必须这样做与上面代码中的代码类似的代码会自动提供给我们。

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

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

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

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

The code you have is equivalent to the following code:

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

Now, all I have done here is remove the syntactic sugar that:

  1. Implements automatic properties.
  2. Works out which members are dealt with relative to this.
  3. Gives all structs a default no-parameter constructor.

The first two are optional (you could write them explicitly if you wished) but the third is not - we aren't allowed to write our own code for a struct's parameterless constructor, we have to go with one that works like the one in the code above being given to us automatically.

Now, looked at here, suddenly the meaning of the two errors becomes clear - your constructor is implicitly using this before it's fields are assigned (error 188) and those fields are those backing the automatic properties (error 843).

It's a combination of different automatic features that normally we don't have to think about, but in this case don't work well. We can fix this by following the advice in the error message for 843 and calling the default constructor as part of your explicit constructor:

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

Considering this in relation to my expanded version of your code above, you can see how this solves the problem, because it calls the constructor that assigns to the backing fields before it proceeds.

能怎样 2024-10-12 10:35:55

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

I would recommend not using auto-properties with structures unless you have a good reason to use them. Wrapping a class field in a read-write property is useful because it makes it possible for an instance to control the circumstances where it may be read or written, and take action when a read or write takes place. Further, code within an object instance can identify the instance being acted upon, and may thus perform a special action only when reading and writing a particular instance. Using an auto-property in an early version of a class will make it possible for future versions of the class to use a manually-implemented property including the aforementioned benefits while retaining compatibility with already-compiled client code. Unfortunately, wrapping a struct field in a read-write property doesn't offer those same benefits because the fields of one struct instance can be copied to another without either instance having any say in the matter. If the semantics of a struct allow a property to be written with arbitrary values in most instances [as would be the case for an auto-property], then any legitimate replacement would be semantically equivalent to a field.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文