Alan başlatıcı, statik olmayan alana, yönteme veya özelliğe başvuruda bulunamaz


96

Bir sınıfım var ve onu başka bir sınıfta kullanmaya çalıştığımda aşağıdaki hatayı alıyorum.

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

    }
}

Sınıfı başka bir sınıfta kullanmak

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

Hata (CS0236):

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

Neden oluyor ve nasıl düzeltilir?

Yanıtlar:


147

Bu hat:

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

Sen başlatmak için bir örnek değişkeni kullanamazsınız başka örnek değişkeni. Neden? Derleyici bu yeniden düzenleyebilirsiniz Çünkü - garantisi yoktur reminderönce başlatılır defaultReminderYukarıdaki satır böylece, belki bir atmak NullReferenceException.

Bunun yerine şunu kullanın:

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

Alternatif olarak, yapıcıdaki değeri ayarlayın:

private dynamic defaultReminder;

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

MSDN - Derleyici Hatası CS0236'da bu derleyici hatasıyla ilgili daha fazla ayrıntı bulunmaktadır .


3
Java, bu tür yapılar için daha 'affedicidir'. Bunun iyi bir şey olup olmadığını bilmiyorum. stackoverflow.com/questions/1494735/…
Wouter Schut

32
Hayır, derleyici başlatıcıları yeniden düzenleyemez. C # Dil Belirtimi, "10.5.5.2 Örnek alanı başlatma" bölümü altında aşağıdakileri belirtir: Değişken başlatıcılar, sınıf bildiriminde göründükleri metin sırasına göre yürütülür. Bu, "10.11.2 Eşgörünüm değişken başlatıcılarında" da tekrarlanır, burada şöyle derler: Değişken başlatıcılar, sınıf bildiriminde göründükleri metin sırasına göre çalıştırılır. Yani açıklamanız yanlış. Sipariş sabitlendi. İzin verilmemesinin nedeni, C # tasarımcılarının bunu böyle istemesidir.
Jeppe Stig Nielsen

(Yalnızca partial classbirkaç dosyada "bölümler" içeren bir durum söz konusu olduğunda , alan başlatıcılarının sırası belirsizdir, ancak bu staticalanlar için de geçerlidir!)
Jeppe Stig Nielsen

@WouterSchut Bağladığınız konu Java ile ilgili değil ?! Aynı zamanda C # ile ilgilidir, ancak staticörnek alanları yerine alanlarla.
Jeppe Stig Nielsen

2
@Andrew Hiç doğru değil, Birçok karar kötü uygulamaları yasaklamak için alınır. teorik olarak uygulanabilir olsalar bile, bazıları Uyarılarla korunur ve bazıları düz Hatalardır. ve bence bu durumlardan biri ... standart sıralı olduğunu söylese de, deneyimli bir geliştirici bile (standardı araştırmadan) kendinden emin bir şekilde söylemez.
Tomer W

22

Bu kodu sınıfınızın kurucusuna koymanız gerekir:

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

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

Bunun nedeni, bir alan başlatıcı kullanarak bir diğerini başlatmak için bir örnek değişkeni kullanamamanızdır.


10

bunun gibi kullanabilirsin

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

11
Stack Overflow'a hoş geldiniz! Bu kod parçacığı soruyu çözebilirken, bir açıklama eklemek, yayınınızın kalitesini artırmaya gerçekten yardımcı olur. Gelecekte okuyucular için soruyu yanıtlayacağınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceklerini unutmayın. Lütfen kodunuzu açıklayıcı yorumlarla doldurmamaya çalışın, çünkü bu hem kodun hem de açıklamaların okunabilirliğini azaltır!
jmattheis

3
= Yerine => kullanıyor ve böylece onu bir özellik yapıyor.
Vincent

3
Bu tekniği kullanırken dikkatli olun, çünkü kullanmak =>gerçek değeri ayarlamaz, ancak her defaultRemindererişildiğinde kodu çalıştırır . Bu amaçlanmış olmayabilir ve performansı olumsuz etkileyebilir veya GC için istenmeyen baskı oluşturabilir, vb.
Smilediver

4

private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];bir alan başlatıcıdır ve ilk olarak yürütülür (başlatıcı olmayan herhangi bir alan varsayılan değerine ayarlanmadan ve çağrılan örnek oluşturucu çalıştırılmadan önce). Başlatıcı içermeyen örnek alanları, tüm örnek alan başlatıcıları tamamlandıktan sonra yalnızca yasal (varsayılan) bir değere sahip olacaktır. Başlatma sırasına bağlı olarak, örnek oluşturucular en son çalıştırılır, bu nedenle örnek, başlatıcıların çalıştırıldığı anda henüz yaratılmaz. Bu nedenle, derleyici, sınıf örneği tam olarak oluşturulmadan önce herhangi bir örnek özelliğinin (veya alanın) başvurulmasına izin veremez. Bunun nedeni , derleyiciye kullanılacak örneğin somut bellek konumunu bildirmek için reminderörtük olarak örneğe ( this) başvuruda bulunarak bir örnek değişkenine herhangi bir erişimdir .

thisÖrnek alan başlatıcısında izin verilmemesinin nedeni de budur .

Bir örnek alanı için değişken başlatıcı, oluşturulan örneğe başvuruda bulunamaz. Bu nedenle, bir değişken başlatıcıda buna başvurmak bir derleme zamanı hatasıdır, çünkü bir değişken başlatıcının herhangi bir örnek üyesine bir basit_isim yoluyla başvurması derleme zamanı hatasıdır .

Örnek alan başlatıcıları çalıştırılmadan önce başlatılması garanti edilen tek tür üyeleri , sınıf (statik) alan başlatıcılar ve sınıf (statik) oluşturucular ve sınıf yöntemleridir. Statik üyeler örnekten bağımsız olduklarından, herhangi bir zamanda bunlara başvurulabilir:

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

Bu nedenle, örnek alan başlatıcılarının yalnızca bir sınıf üyesine (statik üye) başvurmasına izin verilir. Bu derleyici başlatma kuralları, belirleyici bir tür somutlaştırmayı sağlayacaktır.

Daha fazla ayrıntı için bu belgeyi tavsiye ederim: Microsoft Docs: Sınıf bildirimleri .

Bu, değerini başlatmak için başka bir örnek üyesine başvuran bir örnek alanının, örnek oluşturucudan başlatılması veya başvurulan üyenin bildirilmesi gerektiği anlamına gelir static.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.