Een veldinitiator kan niet verwijzen naar het niet-statische veld, de methode of de eigenschap

Ik heb een klas en wanneer ik deze in een andere klas probeer te gebruiken, krijg ik de onderstaande foutmelding.

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

De klas in een andere klas gebruiken

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

Fout (CS0236):

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

Waarom gebeurt het en hoe los je het op?


Antwoord 1, autoriteit 100%

Deze regel:

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

U kunt een instantievariabele niet gebruiken om een andereinstantievariabele te initialiseren. Waarom? Omdat de compiler deze kan herschikken, is er geen garantie dat reminderwordt geïnitialiseerd vóór defaultReminder, dus de bovenstaande regel kaneen NullReferenceException.

Gebruik in plaats daarvan:

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

Als alternatief, stel de waarde in de constructor in:

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

Er zijn meer details over deze compilerfout op MSDN – Compilerfout CS0236.


Antwoord 2, autoriteit 15%

Je moet die code in de constructor van je klas plaatsen:

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

De reden is dat u niet één instantievariabele kunt gebruiken om een andere te initialiseren met behulp van een veldinitiator.


Antwoord 3, autoriteit 7%

je kunt het zo gebruiken

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

Antwoord 4, autoriteit 3%

private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];is een veldinitiator en wordt als eerste uitgevoerd (voordat een veld zonder initialisatie wordt ingesteld op de standaardwaarde en vóór de aangeroepen instantieconstructor wordt uitgevoerd). Instantievelden die geen initializer hebben, hebben pas een legale (standaard) waarde nadat alle initializers van instantievelden zijn voltooid. Vanwege de initialisatievolgorde worden instantieconstructors als laatste uitgevoerd, daarom wordt de instantie nog niet gemaakt op het moment dat de initializers worden uitgevoerd. Daarom kan de compiler niet toestaan dat naar een instantie-eigenschap (of veld) wordt verwezen voordat de klasse-instantie volledig is geconstrueerd. Dit komt omdat elke toegang tot een instantievariabele zoals reminderimpliciet verwijst naar de instantie (this) om de compiler de concrete geheugenlocatie van de instantie te vertellen die moet worden gebruikt.

Dit is ook de reden waarom thisniet is toegestaan in een instantieveldinitialisatie.

Een variabele initialisatie voor een instantieveld kan niet verwijzen naar de
instantie wordt aangemaakt. Het is dus een compile-time fout om naar te verwijzen
dit in een variabele initialisatie, omdat het een compile-time-fout is voor a
variabele initialisatie om naar elk instantielid te verwijzen via a
simple_name.

De enige typeleden die gegarandeerd worden geïnitialiseerd voordatinstantieveldinitialisaties worden uitgevoerd, zijn klasse (statische) veldinitialisaties en klasse (statische) constructors en klassemethoden. Aangezien statische leden instantie-onafhankelijk zijn, kan er op elk moment naar worden verwezen:

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

Daarom mogen initialisaties van instantievelden alleen verwijzen naar een klasselid (statisch lid). Deze compiler-initialisatieregels zorgen voor een deterministische type-instantiatie.

Voor meer details raad ik dit document aan: Microsoft Docs: Class-declaraties.

Dit betekent dat een instantieveld dat verwijst naar een ander instantielid om zijn waarde te initialiseren, moet worden geïnitialiseerd vanuit de instantieconstructor of dat het lid waarnaar wordt verwezen staticmoet worden verklaard.

Other episodes