【问题标题】:Struct constructor: "fields must be fully assigned before control is returned to the caller."结构构造函数:“在将控制权返回给调用者之前,必须完全分配字段。”
【发布时间】:2011-02-01 20:38:24
【问题描述】:

这是我正在尝试编写的结构:

  public struct AttackTraits
        {
            public AttackTraits(double probability, int damage, float distance)
            {
                Probability = probability;
                Distance = distance;
                Damage = damage;
            }

            private double probability;
            public double Probability
            {
                get
                {
                    return probability;
                }
                set
                {
                    if (value > 1 || value < 0)
                    {
                        throw new ArgumentOutOfRangeException("Probability values must be in the range [0, 1]");
                    }
                    probability = value;
                }
            }

            public int Damage { get; set; }

            public float Distance { get; set; }
        }

这会导致以下编译错误:

“this”对象不能使用 在分配其所有字段之前 到

字段 'AttackTraits.probability' 必须 在控制之前被完全分配 返回给调用者

自动支持字段 实现的属性 'AttackTraits.Damage' 必须完全 在控制权返回之前分配 呼叫者,召集者。考虑调用 来自构造函数的默认构造函数 初始化器。

自动支持字段 实现的属性 'AttackTraits.Distance' 必须完全 在控制权返回之前分配 呼叫者,召集者。考虑调用 来自构造函数的默认构造函数 初始化器。

我做错了什么?

【问题讨论】:

    标签: c# constructor struct


    【解决方案1】:

    如果您在具有自动属性的结构上看到此错误,只需通过执行以下 : this() 示例从您的参数化构造器中调用无参数构造器:

    struct MyStruct
    {
      public int SomeProp { get; set; }
    
      public MyStruct(int someVal) : this()
      {
         this.SomeProp = someVal;
      }
    }
    

    通过在构造函数声明中调用 :this(),您可以让基础 ValueType 类初始化自动属性的所有支持字段。我们无法在构造函数上手动执行此操作,因为我们无权访问自动属性的支持字段。 ValueType 是所有结构体的基类。

    【讨论】:

    • @ChrisAmelinckx 你在哪里可以找到所有这些看起来像是某人的想象的东西,尽管只有它才能真正起作用(:
    • 这行得通,但我不明白为什么。谁能解释一下?为什么必须先调用无参数构造函数?我错过了一些东西......
    • @DarrenHale 当构造函数的第一行要执行时,对于结构,所有字段都需要已经初始化。 SomeProp 是一个自动属性,相当于拥有一个显式的“someProp”字段和 get/set 方法。通过调用基础无参数 : this() 构造函数,您可以保证在构造函数中“您的逻辑”的第一行之前,所有字段都已初始化。
    • 我们有解决方案很酷,但究竟为什么需要这种解决方法?
    • @Peter,您提出了一个很好的观点,这似乎是一种解决方法。我的观点是,这不是一种解决方法,而是该问题的完整解决方案。结构是应用程序状态的轻量级表示,可以复制到执行堆栈上。 (每次将值类型实例(结构)传递给方法时,都会在该方法的上下文中创建它的新副本,而不是传递类定义对象类型的引用)。
    【解决方案2】:

    尝试访问概率字段而不是访问器。在这种情况下,自动道具也应该可以工作。

    结构体无法拥有无参数构造函数,因此请考虑将其改为类。

    最佳实践是仅在 16 字节或更少且不可变的情况下使用结构。因此,如果您要在创建后更改对象字段,请考虑将其重构为类。

    此外,您可以将构造函数定义更改为:

    construct(params) : this()
    

    这也将消除错误

    【讨论】:

    • 仅供参考,您的答案有效,但您的某些理由不正确。事实上,结构总是有一个无参数的构造函数。与类不同,结构的无参数构造函数不能通过创建带参数的构造函数来隐藏。
    • 不要不必要地强调这一点,但调用该构造函数不仅完全合法,而且它会像任何其他构造函数一样以智能感知弹出。你能提供一个不正确的案例吗?
    • @joshua.ewer, @vittore - 你总是被允许调用那个构造函数,你不能做的是给你自己的实现,但必须始终使用给你的默认值(将default(AppropriateType) 分配给所有实例字段)。
    • @kashif 你可以根据它的字段大小来计算它。
    【解决方案3】:

    您正在通过Probability 属性设置probability 字段,但编译器不知道该属性设置了该字段...因此您需要显式初始化概率字段本身

    public AttackTraits(double probability, int damage, float distance)
    {
        this.probability = 0;
        Distance = distance;
        Damage = damage;
    }
    

    【讨论】:

    • 试过这个。对我不起作用 - 但我正在使用自动属性
    • @RogerWillcocks,然后调用默认构造函数:public YourStruct(some params) : this()(见 vittore 的回答)
    • 这个解决方案的问题。您没有 Probability 属性的验证优势。它并不能解决所有问题,因为您还需要将 DistanceDamage 更改为非匿名属性,否则它将无法正常工作。我更喜欢 @Chris-Amelinckx 的回答作为更好的解决方案。
    • 努力使 c#7 代码向后兼容:当您删除现有的自动属性初始化程序时它会弹出(与 OP 代码中的原因相同)。请注意,在这种情况下,实际答案是上面的@thomas 注释(虽然您不能在结构上拥有显式默认构造函数,但可以在构造函数链中调用它)> 您能否将其编辑到您的答案中,因为 cmets 可能会被删除?
    【解决方案4】:

    Probability = probability这一行改为this.probability = probability

    将来为字段选择不同的命名约定,就像为参数选择不同的命名约定一样。例如,为所有字段添加下划线前缀,因此您可以简单地调用它:

    _probability = probability;
    

    并轻松查看正在发生的事情。

    【讨论】:

    • 是的,只是参数和字段之间存在丑陋的名称冲突。
    【解决方案5】:

    尝试为 AttackTraits

    struct 更改为 class
    public class AttackTraits
            {
    .........
            {
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多