Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 编译错误。将属性与结构一起使用_C#_Struct_Compiler Errors_Language Features - Fatal编程技术网

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

C# 编译错误。将属性与结构一起使用,c#,struct,compiler-errors,language-features,C#,Struct,Compiler Errors,Language Features,请解释结构构造函数上的以下错误。如果我将struct更改为class 错误消失了 public struct DealImportRequest { public DealRequestBase DealReq { get; set; } public int ImportRetryCounter { get; set; } public DealImportRequest(DealRequestBase drb) { DealReq = drb

请解释结构构造函数上的以下错误。如果我将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”必须在控制返回给调用方之前完全分配。考虑从构造函数初始化器调用默认构造函数。

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

public DealImportRequest(DealRequestBase drb) : this()
{
   DealReq = drb;
   ImportRetryCounter = 0;
}
根据语言规范:

10.7.3自动实现的属性

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

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


请注意,这里的结构是可变的。我建议您要么将类型设置为类(您的编译问题应该立即消失),要么将类型设置为不可变。假设您提供的代码是整个结构,实现这一点的最简单方法是将setter设置为私有(
get;private set;
)。当然,您还应该确保以后不会向结构添加任何依赖私有访问修改字段的变异方法。或者,您可以使用
只读
备份字段来备份属性,并完全取消设置程序。

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

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;
    }
}
现在,我在这里所做的就是去掉语法上的糖分:

  • 实现自动属性
  • 计算出与此相关的要处理的成员
  • 为所有
    struct
    s提供默认的无参数构造函数
  • 前两个是可选的(如果愿意,您可以显式地编写它们),但第三个不是-我们不允许为
    struct
    的无参数构造函数编写自己的代码,我们必须使用与上面代码中自动提供给我们的构造函数类似的代码

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

    这是一个不同的自动功能的组合,通常我们不必考虑,但在这种情况下,工作不好。我们可以按照843错误消息中的建议并调用默认构造函数作为显式构造函数的一部分来修复此问题:

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

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

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

    可能重复@Hps,我不同意。虽然它确实与该问题中的问题相关,但它相对于隐式字段(支持自动属性)而不是显式字段这样做的事实足以阻止人们看到这两个问题相关的原因。这应该足以考虑他们不是重复IMO。你是正确的。谢谢你的解释。我应该更加小心:)