Инициализатор поля не может ссылаться на нестатическое поле, метод или свойство
У меня есть класс, и когда я пытаюсь использовать его в другом классе, я получаю ошибку ниже.
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
Почему это происходит и как его исправить?
Ответы
Ответ 1
Эта строка:
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.
Ответ 2
Вам нужно поместить этот код в конструктор вашего класса:
private Reminders reminder = new Reminders();
private dynamic defaultReminder;
public YourClass()
{
defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}
Причина в том, что вы не можете использовать одну переменную экземпляра для инициализации другой с помощью инициализатора поля.
Ответ 3
вы можете использовать это как
private dynamic defaultReminder => reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
Ответ 4
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: объявления классов.
Это означает, что поле экземпляра, которое ссылается на другой элемент экземпляра для инициализации его значения, должно быть инициализировано из конструктора экземпляра, или указанный элемент должен быть объявлен static
.