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

时间:2013-01-21 13:01:07

标签: c#

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

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

    }
}

在另一个班级中使用该课程

class SomeOtherClass
{  
    private Reminders reminder = new Reminders();
    // error happens on this line:
    private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
    ....

错误(CS0236):

A field initializer cannot reference the nonstatic field, method, or property

为什么会发生以及如何解决?

4 个答案:

答案 0 :(得分:109)

这一行:

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

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

相反,只需使用:

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

或者,在构造函数中设置值:

private dynamic defaultReminder;

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

有关MSDN上此编译器错误的更多详细信息 - Compiler Error CS0236

答案 1 :(得分:21)

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

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

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

原因是你不能使用一个实例变量来使用字段初始值设定项初始化另一个实例变量,因为字段初始化程序的执行顺序是未定义的。

答案 2 :(得分:6)

你可以像这样使用

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

答案 3 :(得分:2)

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

这也是为什么实例字段初始化程序中不允许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)];
}

这就是为什么只允许实例字段初始化程序引用类成员(静态成员)的原因。该编译器初始化规则将确保确定性类型实例化。

有关更多详细信息,我建议使用此文档:Microsoft Docs: Class declarations

这意味着引用另一个实例成员以初始化其值的实例字段必须从实例构造函数中初始化,否则必须声明所引用的成员static