字段初始值设定项不能引用非静态字段、方法或属性
本文关键字:字段 静态 方法 属性 引用 不能 | 更新日期: 2023-09-27 17:55:12
我有一个类,当我尝试在另一个类中使用它时,我收到以下错误。
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
为什么会发生这种情况以及如何解决?
这一行:
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 上有有关此编译器错误的更多详细信息 - 编译器错误 CS0236。
您需要将该代码放入类的构造函数中:
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 = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
是一个字段初始值设定项,首先执行(在任何没有初始值设定项的字段设置为其默认值之前,在执行调用的实例构造函数之前)。没有初始值设定项的实例字段仅在完成所有实例字段初始值设定项后才具有合法(默认)值。由于初始化顺序,实例构造函数最后执行,这就是为什么在执行初始值设定项时尚未创建实例的原因。因此,编译器不允许在完全构造类实例之前引用任何实例属性(或字段)。这是因为任何对实例变量(如reminder
)的访问都会隐式引用实例(this
),以告诉编译器要使用的实例的具体内存位置。
这也是实例字段初始值设定项中不允许使用 this
的原因。
保证在执行实例字段初始值设定项实例字段的变量初始值设定项不能引用 正在创建的实例。因此,引用它是一个编译时错误 这在变量初始值设定项中,因为它是 变量初始值设定项,用于通过 simple_name。
之前初始化的唯一类型成员是类(静态)字段初始值设定项和类(静态)构造函数和类方法。由于静态成员与实例无关,因此可以随时引用它们:
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文档:类声明。
这意味着引用另一个实例成员以初始化其值的实例字段必须从实例构造函数初始化,或者必须将引用的成员声明为static
。
我对社区在这里接受的答案感到非常惊讶,这是完全错误的,接受的答案说:
因为编译器可以重新排列这些
正如"Jeppe Stig Nielsen"在接受答案的评论中所说:
C# 语言规范指出: 变量初始值设定项是按照它们在类中出现的文本顺序执行声明
这并不意味着 C# 是一种解释语言,但也不意味着 C# 可以重新排列代码行!
那么最后为什么会发生此错误?假设以下代码:
public class MyClass
{
public int i = 5;
public int j = i; // CS0236
public MyClass()
{
// ...
}
}
让我向您展示 C# 编译器如何看待此代码:
public class MyClass
{
public int i = 5;
public int j = this.i; // CS0236
public MyClass()
{
// ...
}
}
"this"关键字出现在类MyClass
public int j = this.i;
引用中,但MyClass
还不存在,为什么? 因为类在其构造函数结束执行时开始存在,而在 C# 逻辑构造函数中最后执行,这意味着它们将在实例字段/变量初始值设定项之后执行,所以public int j = this.i;
表达式中,this
什么都不引用!
你应该在构造函数中初始化。所以这样做:
class SomeOtherClass
{
private Reminders reminder ;
// error happens on this line:
private dynamic defaultReminder ;
public SomeOtherClass()
{
remider = new Reminders();
defaultReminder =reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}