C# 字段初始值设定项不能引用非静态字段、方法或属性

C# 字段初始值设定项不能引用非静态字段、方法或属性,c#,C#,我有一个类,当我尝试在另一个类中使用它时,我收到下面的错误 using System; using System.Collections.Generic; using System.Linq; namespace MySite { public class Reminders { public Dictionary<TimeSpan, string> TimeSpanText { get; set; } // We are sett

我有一个类,当我尝试在另一个类中使用它时,我收到下面的错误

using System;
using System.Collections.Generic;
using System.Linq;

namespace MySite
{
    public class Reminders
    {
        public Dictionary<TimeSpan, string> TimeSpanText { get; set; }

        // We are setting the default values using the Costructor
        public Reminders()
        {
            TimeSpanText.Add(TimeSpan.Zero, "None");
            TimeSpanText.Add(new TimeSpan(0, 0, 5, 0), "5 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 15, 0), "15 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 30, 0), "30 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 1, 0, 0), "1 hour before");
            TimeSpanText.Add(new TimeSpan(0, 2, 0, 0), "2 hours before");
            TimeSpanText.Add(new TimeSpan(1, 0, 0, 0), "1 day before");
            TimeSpanText.Add(new TimeSpan(2, 0, 0, 0), "2 day before");
        }

    }
}
错误(CS0236):

为什么会发生这种情况以及如何解决它?

这一行:

private dynamic defaultReminder = 
                          reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
不能使用实例变量初始化另一个实例变量。为什么?因为编译器可以重新排列它们-不能保证
提醒
将在
默认提醒
之前初始化,因此上面的行可能会抛出
NullReferenceException

相反,只需使用:

private dynamic defaultReminder = TimeSpan.FromMinutes(15);
或者,在构造函数中设置值:

private dynamic defaultReminder;

public Reminders()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
}

MSDN-上有关于此编译器错误的更多详细信息。

您需要将该代码放入类的构造函数中:

private Reminders reminder = new Reminders();
private dynamic defaultReminder;

public YourClass()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}
原因是不能使用字段初始值设定项使用一个实例变量来初始化另一个实例变量。

可以这样使用

private dynamic defaultReminder => reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 

private dynamic defaultReminder=提醒.TimeSpanText[TimeSpan.FromMinutes(15)]
是字段初始值设定项并首先执行(在没有初始值设定项的任何字段设置为其默认值之前,以及在执行调用的实例构造函数之前)。没有初始值设定项的实例字段只有在完成所有实例字段初始值设定项后才具有合法(默认)值。由于初始化顺序,实例构造函数是最后执行的,这就是为什么在执行初始化器时还没有创建实例的原因。因此,在类实例完全构造之前,编译器不能允许引用任何实例属性(或字段)。这是因为对实例变量(如
rementer
)的任何访问都会隐式引用实例(
This
),以告知编译器要使用的实例的具体内存位置

这也是为什么在实例字段初始值设定项中不允许使用此

实例字段的变量初始值设定项不能引用 正在创建的实例。因此,引用是编译时错误 这是变量初始值设定项中的错误,因为它是 变量初始值设定项,通过 简单的名字

确保在执行实例字段初始值设定项之前初始化的唯一类型成员是类(静态)字段初始值设定项和类(静态)构造函数以及类方法。由于静态成员与实例无关,因此可以随时引用它们:

class SomeOtherClass
{
  private static Reminders reminder = new Reminders();

  // This operation is allowed,
  // since the compiler can guarantee that the referenced class member is already initialized
  // when this instance field initializer executes
  private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}
这就是为什么实例字段初始值设定项只允许引用类成员(静态成员)。此编译器初始化规则将确保确定性类型实例化

有关更多详细信息,我建议使用以下文档:


这意味着引用另一个实例成员来初始化其值的实例字段必须从实例构造函数中初始化,或者引用的成员必须声明为
静态

Java对于此类构造更为“宽容”。我不知道这是否是件好事。不,编译器无法重新排列初始值设定项。C#语言规范在“10.5.5.2实例字段初始化”一节中规定:变量初始值设定项按照类声明中出现的文本顺序执行。这甚至在“10.11.2实例变量初始值设定项”中重复,其中他们说:变量初始值设定项是按照类声明中出现的文本顺序执行的。所以你的解释是错误的。顺序是固定的。它被禁止的原因是C#的设计者希望这样做(只有在多个文件中有“部分”的
部分类
的情况下,字段初始值设定项的顺序不清楚,但这也适用于
静态
字段!)Wouterschu你链接的线程不是关于Java的吗?!它也是关于C#的,但是使用
静态
字段而不是实例字段。@Andrew一点也不正确,许多决定都是为了禁止不良做法。尽管理论上它们可以实现,但有些由警告保护,有些则是明显的错误。我认为这是其中一个例子。。。即使标准说它是顺序的,即使是有经验的开发人员也不会自信地说(不搜索标准)。欢迎使用Stack Overflow!虽然这个代码片段可以解决这个问题,但是包含一个真正有助于提高文章质量的代码片段。请记住,您将在将来回答读者的问题,这些人可能不知道您的代码建议的原因。还请尽量不要用解释性注释挤满您的代码,因为这会降低代码和解释的可读性!它使用=>而不是=从而使其成为一个属性。使用此技术时要小心,因为使用
=>
不会设置实际值,但每次访问
defaultrementer
时都会执行代码。这可能不是故意的,并且会对性能产生负面影响,或对GC产生不必要的压力等。
private dynamic defaultReminder => reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
class SomeOtherClass
{
  private static Reminders reminder = new Reminders();

  // This operation is allowed,
  // since the compiler can guarantee that the referenced class member is already initialized
  // when this instance field initializer executes
  private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}