2010-02-25 15 views
32

Jeśli mogę to zrobić otrzymuję System.StackOverflowException:Dlaczego kompilator C# nie przestaje odwoływać się do właściwości?

private string abc = ""; 
public string Abc 
{ 
    get 
    { 
     return Abc; // Note the mistaken capitalization 
    } 
} 

rozumiem dlaczego - nieruchomość jest odwołanie się, co prowadzi do nieskończonej pętli. (Zobacz poprzednie pytania here i here).

Zastanawiam się (i czego nie widziałem odpowiedział w poprzednich pytaniach), dlaczego kompilator C# nie złapie tego błędu? Sprawdza inne rodzaje odwołań cyklicznych (klasy dziedziczące od siebie itp.), Prawda? Czy to tylko ten błąd nie był na tyle powszechny, aby warto było go sprawdzić? Czy jest jakaś sytuacja, o której nie myślę, kiedy chciałbyś, aby nieruchomość rzeczywiście się w ten sposób odwoływała?

+2

Przez "odniesienie się", przypuszczam, że naprawdę chcę powiedzieć "rekurencyjnie nazywając siebie", ale masz pomysł. –

Odpowiedz

42

Możesz zobaczyć "oficjalny" powód w ostatnim komentarzu here.

Wysłany przez Microsoft w dniu 14/11/2008 w 19:52

Dzięki za sugestię dla Visual Studio!

Masz rację, że możemy łatwo wykryć właściwość rekursji, ale nie może zagwarantować, że nie ma nic przydatna jest realizowane poprzez rekursji. Ciało nieruchomości może ustawić inne pola na swoim obiekcie które zmieniają zachowanie następnego rekursji, może zmienić swoje zachowanie w oparciu o dane wprowadzone przez użytkownika z konsoli, lub może nawet zachowywać się różnie w oparciu na wartości losowych. W takich przypadkach właściwość samokonkurencyjna może w istocie sprawić, że zakończy rekursję, ale mamy nie można ustalić, czy jest to przypadek podczas kompilacji (bez rozwiązywania problemu zatrzymania!).

Z powodów wyżej (i łamiącym zmianę zajęłoby nie pozwalają na takie), nie byłyby w stanie zakazać właściwości samo-rekurencyjne.

Alex Turner

Program Manager

Visual C# Compiler

+20

Może być jednak przyjemnie, jeśli wygenerują ostrzeżenie kompilatora. Myślę, że byłoby to cenne. – Nick

+0

+1 Niezła, pełna odpowiedź z "oficjalnego" źródła. – auujay

+0

Ma sens. . . Czy można bezpiecznie powiedzieć, że prawdopodobnie nie jest to * dobry pomysł *, aby celowo uzyskać rekurencyjną właściwość gettera, ponieważ zatrzymał by się tylko wtedy, gdyby wystąpiły efekty uboczne i (jeśli dobrze rozumiem), metody są preferowane w stosunku do właściwości w przypadkach, gdy są efekty uboczne? –

1

Prawdopodobnie uważali, że niepotrzebnie komplikował by kompilator bez rzeczywistego zysku.

Ta literówka zostanie łatwo odkryta podczas pierwszego wywołania tej właściwości.

0

innych przypadkach sprawy, które sprawdza go pod względem (oprócz rekurencyjnego konstruktora) są nieważne IL.
Ponadto wszystkie te przypadki, nawet konstruktory rekursywne, są zabezpieczone przed niepowodzeniem.

Możliwe jest jednak, choć mało prawdopodobne, celowe utworzenie użytecznej właściwości rekurencyjnej (za pomocą instrukcji if).

9

Właściwość odnoszącą się do siebie nie zawsze prowadzi do nieskończonej rekurencji i przepełnienia stosu. Na przykład, to działa prawidłowo:

int count = 0; 
public string Abc 
{ 
    count++; 
    if (count < 1) return Abc; 
    return "Foo"; 
} 

Powyżej znajduje się atrapa przykład, ale jestem pewien, że można wymyślić użytecznego kodu rekurencyjnego, który jest podobny. Kompilator nie może określić, czy dojdzie do nieskończonej rekurencji (problem z zatrzymaniem).

Generowanie ostrzeżenia w prostym przypadku byłoby pomocne.

1

Przede wszystkim otrzymasz ostrzeżenie o nieużywanej zmiennej abc.

Po drugie, nie ma nic złego w rekurencji, pod warunkiem, że nie jest to nieskończona rekursja. Na przykład kod może dostosować niektóre wewnętrzne zmienne i wywoływać rekurencyjnie ten sam getter. Jednak dla kompilatora nie ma łatwego sposobu udowodnienia, że ​​rekursja jest nieskończona lub nie (zadanie to przynajmniej NP). Kompilator mógłby złapać kilka łatwych przypadków, ale wtedy konsumenci byliby zaskoczeni, że bardziej skomplikowane przypadki przechodzą przez kontrole kompilatora.

11

Kolejnym punktem oprócz wyjaśnienia Alexa jest to, że staramy się podawać ostrzeżenia dla kodu, który robi coś, co prawdopodobnie nie było zamierzone, tak, że można przypadkowo wysłać z błędem.

W tym konkretnym przypadku, ile czasu to ostrzeżenie faktycznie zaoszczędziłoby? Pojedynczy przebieg testu. Znajdziesz ten błąd w momencie testowania kodu, ponieważ zawsze natychmiast się zawiesza i umiera straszliwie. Ostrzeżenie w rzeczywistości nie przyniosłoby ci znacznej korzyści. Prawdopodobieństwo pojawienia się subtelnego błędu w ocenie właściwości rekursywnej jest niewielkie.

Natomiast robimy dać ostrzeżenie, jeśli można zrobić coś takiego:

int customerId; 
... 
this.customerId= this.customerId; 

nie ma okropny trzask-and-die, a kod jest poprawny kod; przypisuje wartość do pola. Ale ponieważ jest to bezsensowny kod, prawdopodobnie nie chciałeś tego zrobić. Ponieważ nie umrze strasznie, ostrzegamy, że jest coś, czego prawdopodobnie nie zamierzaliście i nie moglibyście inaczej odkryć przez awarię.

+0

Omawiałem te komentarze na temat odpowiedzi Alexa. Twoje stwierdzenie, że "Ale skoro to jest bezsensowny kod, prawdopodobnie nie chciałeś tego zrobić. Ponieważ nie umrze strasznie, ostrzegamy cię, że jest coś, czego prawdopodobnie nie zamierzałeś" wydaje się przeczyć twojemu blogowi publikuj tutaj: http://blogs.msdn.com/ericlippert/archive/2010/01/25/why-are-unused-using-directives-not-a-warning.aspx – Nick

+1

@Nick: Nie widzę sprzeczność. (To nie znaczy, że nie ma nikogo: jestem duży, mam tłumy.) Po prostu nie widzę, do czego zmierzasz. –

+0

@Eric Lippert: Dziękuję za odniesienie do Song of Myself. :-) – jason

Powiązane problemy