【问题标题】:I need to reference a variable from a non static class in a non static class constructor. [c#]我需要在非静态类构造函数中引用非静态类的变量。 [C#]
【发布时间】:2018-06-29 17:17:30
【问题描述】:

我正在尝试用天然卫星制作一个太阳系。目前我正在绘制一个相对于静态“太阳”类对象的行星,但我想让该类使用另一个行星对象的位置并相对于该行星进行绘制。为此,我需要提取该行星对象的 x 和 y 位置。

这是我用来绘制行星的类的类构造函数。

Nebesko_Telo merkur = new Nebesko_Telo(Sun.x, Sun.y, 4, 12, 4.090909090909091,
                                       1, 255, 255, 255);
// A field initializer cannot reference the non-static field, method,
//    or property 'Form1.merkur'.
Nebesko_Telo venera = new Nebesko_Telo(merkur.x, merkur.y, 1, 23, 1.5, 1, 176, 108, 32);

这是类构造函数。

public Nebesko_Telo(doubl _rel_tel_x, double _rel_tel_y, double _r, double _or,
                    double _Fi_mult, double _tilt_plant_nat, int _re, int_gr, int _bl) {
    r = _r;
    or = _or;
    Fi_mult = _Fi_mult;
    re = _re;
    gr = _gr;
    bl = _bl;
    tilt_planet_nat = _tilt_planet_nat;
    rel_tel_x = _rel_tel_x;
    rel_tel_y = _rel_tel_y;
}

x 和 y 位置会随着每个刻度不断更新,所以我需要它不断更新它:^/.

【问题讨论】:

  • 主要建议 - 尽量不要使用静态。相反,请阅读控制反转依赖注入以及一般来说什么是服务定位器。您的问题实际上是一个很常见的问题,IoC 概念极大地帮助您在专业开发人员的水平上开发应用程序。
  • 欢迎来到 SO。请发布Minimal, Complete, and Verifiable Example,以便您的问题可以重现。另外,不要链接到屏幕截图,请在此处复制粘贴代码的相关部分。
  • 请不要将代码截图发布到 SO,除非您的问题实际上是关于调试器 UI 的某些元素。它很难阅读,我们不能剪切粘贴,等等。
  • 相反,将代码(和任何错误消息)剪切并粘贴到答案中,然后使用代码格式化工具。
  • 您可以考虑使用的两种技术是 (1) 使您的数据结构不可变。也就是说,太阳系在特定时间的快照。当您进行时间步长时,您会创建一个 new 快照。这真的不会消耗那么多内存。行星在特定时间的轨道特征可以用几十个双倍来概括,以达到一个很好的近似值。这意味着您可以轻松地存储快照、向前和向后运行模拟等等。推断一致的数据也更容易,因为它不会改变。

标签: c# class constructor static non-static


【解决方案1】:

在字段初始化器中以 any 方式使用this 是非法的。 merkurvenera 的初始化程序中实际上是 this.merkur,所以它很重要。

C# 可以防止这种情况发生,因为该技术是常见的错误来源。字段初始值设定项构造函数体之前运行,包括基类构造函数的构造函数体。如果 C# 没有限制您访问 this,那么访问属性或调用尚未准备好使用的方法将非常容易。

有关构造函数初始化程序运行顺序的更多详细信息,请参阅https://blogs.msdn.microsoft.com/ericlippert/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one/

您应该做的是将所有字段初始化程序移到构造函数主体中。然后你有责任确保正文中的语句以正确的顺序运行以进行你想要的初始化。

【讨论】:

    【解决方案2】:

    simple Google search 中的第一次点击应该可以解决这个问题。

    本质上,您的问题是您在代码中使用一个实例变量 (merkur) 来初始化另一个实例变量 (venera)。

    这是不允许的,因为不能保证merkur 会在venera 之前初始化,所以编译器不喜欢这样。

    假设merkur.xSun.x 相同,您也可以使用它来初始化venera

    【讨论】:

      【解决方案3】:

      编译器不允许您使用另一个实例字段的属性来初始化一个实例字段。相反,我建议在首先执行的任何方法(例如 Form.Load 事件)中初始化您的字段。这将允许您在处理任何信息之前正确初始化您的字段。例如:

      Nebesko_Telo merkur = null;
      Nebesko_Telo venera = null;
      private void Form1_Load(object sender, EventArgs e) {
          merkur = new Nebesko_Telo(Sun.x, Sun.y, 4, 12, 4.090909090909091, 1, 255, 255, 255);
          if (merkur != null)
              venera = new Nebesko_Telo(merkur.x, merkur.y, 1, 23, 1.5, 1, 176, 108, 32);
      }
      

      绝对可以随意参考其他答案提供的文章,this post 也应该对该主题有所了解,因为那里接受的答案提供了一些很好的细节,说明为什么这个问题是一个实际问题。引用以防链接失效:

      您不能使用实例变量来初始化另一个实例变量。为什么?因为编译器可以重新排列这些 - 不能保证 reminder 会在 defaultReminder 之前初始化,所以上面的行可能会在运行时抛出 NullReferenceException

      还可以随时查看 Microsoft 的 Compiler Error CS0236 参考。它应该进一步阐明这个主题。

      实例字段不能用于初始化方法之外的其他实例字段。如果您尝试在方法外初始化变量,请考虑在类构造函数内执行初始化。如需更多信息,请参阅Methods

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-25
        • 2014-01-22
        • 2011-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多