Un inițializator de câmp nu poate face trimitere la un câmp, metodă sau proprietate nestatică. (Programare, C#)

GibboK a intrebat.
a intrebat.

Am o clasă și când încerc să o folosesc într-o altă clasă primesc eroarea de mai jos.

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

    }
}

Utilizarea clasei în altă clasă

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

Eroare (CS0236):

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

De ce se întâmplă și cum se remediază?

4 răspunsuri
Oded

Această linie:

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

Nu puteți utiliza o variabilă de instanță pentru a inițializa o alta variabilă de instanță. De ce? Pentru că compilatorul le poate rearanja – nu există nicio garanție că reminder va fi inițializată înainte de defaultReminder, , astfel încât linia de mai sus ar putea fi arunca un NullReferenceException.

În schimb, utilizați doar :

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

Alternativ, setați valoarea în constructor:

private dynamic defaultReminder;

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

Există mai multe detalii despre această eroare de compilare pe MSDN – Eroare de compilare CS0236.

Comentarii

  • Java este mai „iertător” pentru acest tip de construcții. Nu știu dacă acesta este un lucru bun. stackoverflow.com/questions/1494735/… – –  > Por Wouter Schut.
  • 32

  • Nu, compilatorul nu poate rearanja inițializatoarele. Specificația limbajului C# precizează, la secțiunea „10.5.5.5.2 Initializarea câmpurilor de instanță”, următoarele: „10.5.5.2 Initializarea câmpurilor de instanță”: Inițializatoarele de variabile sunt executate în ordinea textuală în care apar în declarația clasei. Acest lucru se repetă chiar și în „10.11.2 Instance variable initializers”, unde se spune: „10.11.2 Instance variable initializers”: Inițializatoarele de variabile se execută în ordinea textuală în care apar în declarația clasei. Așadar, explicația dumneavoastră este greșită. Ordinea este fixă. Motivul pentru care nu este permisă este că așa au vrut proiectanții C#. –  > Por Jeppe Stig Nielsen.
  • (Numai în cazul unui partial class cu „părți” în mai multe fișiere este neclară ordinea inițializatorilor de câmp, dar acest lucru este valabil și pentru static câmpuri, de asemenea!) –  > Por Jeppe Stig Nielsen.
  • @WouterSchut Firul de discuție pe care îl linkați nu se referă la Java?! Este vorba despre C#, de asemenea, cu toate acestea, cu static în loc de câmpuri de instanță. –  > Por Jeppe Stig Nielsen.
  • @Andrew Nu este adevărat deloc, Multe decizii sunt luate pentru a interzice practicile proaste. chiar dacă, teoretic, pot fi implementate, unele sunt păzite de avertismente, iar altele sunt simple erori. și cred că acesta este unul dintre aceste cazuri… chiar dacă standardul spune că este secvențial, nici măcar un dezvoltator cu experiență nu ar spune-o cu încredere (fără să caute în standard). –  > Por Tomer W.
Daniel Hilgarth

Trebuie să pui acel cod în constructorul clasei tale:

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

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

Motivul este că nu poți folosi o variabilă de instanță pentru a inițializa o alta folosind un inițializator de câmp.

jin wang

puteți utiliza astfel

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

Comentarii

  • Bine ați venit la Stack Overflow! Deși acest fragment de cod poate rezolva întrebarea, includerea unei explicații ajută cu adevărat la îmbunătățirea calității mesajului dumneavoastră. Amintiți-vă că răspundeți la întrebare pentru cititorii din viitor, iar acele persoane ar putea să nu cunoască motivele pentru sugestia dvs. de cod. De asemenea, vă rugăm să încercați să nu aglomerați codul cu comentarii explicative, deoarece acest lucru reduce lizibilitatea atât a codului, cât și a explicațiilor! –  > Por jmattheis.
  • Folosește => în loc de =, făcând astfel din el o proprietate. –  > Por Vincent.
  • Aveți grijă la utilizarea acestei tehnici, deoarece utilizarea => nu setează valoarea reală, ci va executa codul de fiecare dată când defaultReminder este accesată. Este posibil ca acest lucru să nu fie intenționat și să aibă un impact negativ asupra performanței sau să genereze o presiune nedorită pentru GC, etc. –  > Por Smilediver.
BionicCode

private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; este un inițializator de câmp și se execută primul (înainte ca orice câmp fără inițializator să fie setat la valoarea sa implicită și înainte de a fi executat constructorul instanței invocate). Câmpurile de instanță care nu au inițializator vor avea o valoare legală (implicită) numai după ce toate inițializatoarele câmpurilor de instanță sunt finalizate. Din cauza ordinii de inițializare, constructorii de instanță sunt executați ultimii, motiv pentru care instanța nu este încă creată în momentul în care se execută inițializatorii. Prin urmare, compilatorul nu poate permite ca o proprietate de instanță (sau câmp) să fie menționată înainte ca instanța clasei să fie complet construită. Acest lucru se datorează faptului că orice acces la o variabilă de instanță precum reminder face trimitere implicită la instanță (this) pentru a indica compilatorului locația de memorie concretă a instanței care trebuie utilizată.

Acesta este, de asemenea, motivul pentru care this nu este permis într-un inițializator de câmp de instanță.

Un inițializator de variabilă pentru un câmp de instanță nu poate face trimitere la instanța creată. Prin urmare, este o eroare de compilare să se facă referire la acesta într-un inițializator de variabile, așa cum este o eroare de compilare ca un inițializator de variabile să facă referire la orice membru de instanță prin intermediul unui câmp de instanță. simple_name.

Singurii membri de tip care sunt garantați a fi inițializați înainte de inițializatorii câmpurilor de instanță sunt inițializatorii câmpurilor de clasă (statice) și constructorii și metodele de clasă (statice). Deoarece membrii statici sunt independenți de instanță, aceștia pot fi referiți în orice moment:

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

De aceea, inițializatorii de câmpuri de instanță pot face referire numai la un membru de clasă (membru static). Aceste reguli de inițializare ale compilatorului vor asigura o instanțiere deterministă a tipului.

Pentru mai multe detalii, vă recomandăm acest document: Microsoft Docs: Declarații de clasă.

Acest lucru înseamnă că un câmp de instanță care face referire la un alt membru de instanță pentru a-și inițializa valoarea, trebuie inițializat din constructorul instanței sau membrul la care se face referire trebuie să fie declarat static.

Tags: