2017-04-19 1 views
4

Ich könnte hier einige downvotes bekommen, aber ich habe tatsächlich widersprüchliche Informationen durch normale Suchen gefunden und möchte eine definitive Antwort andere Leute können auch leicht finden.Wie werden C# 6.0-Standardeigenschaftswerte beim Verwenden von Funktionsaufrufen durch den Bereich zugewiesen und beeinflusst?

eine Eigenschaft in der aktuellen C# Gegeben:

public static IEnumerable<string> foo { get; set; } = new string[] { "bar", "bar2" }; 

Wir wissen, dass der Standardwert von foo wie das obige Array zurück. Wenn ein anderer Wert zugewiesen wird, wird der Standardwert nicht mehr verwendet. Was aber, wenn der Fall ist:

public static IEnumerable<string> foo { get; set; } = GetMyStrings(); 

Mein Gedanke ist, dass diese Funktionen wie:

if(foo == null) { foo = GetMyStrings();} 

und dass foo wird der Wert von seinem ersten Lauf von GetMyStrings() für die Lebensdauer des Objekts beibehalten, es sei denn überschrieben durch einen manuell zugewiesenen Wert.

Mein Kollege besteht darauf, dass dies ein GC-Problem birgt, und dass das Ergebnis GetMyStrings() außerhalb des Geltungsbereichs fallen und gesammelt werden kann, den Parameter "renullifying" und mehrere Aufrufe an GetMyStrings() über die Lebensdauer des Objekts verursacht.

Wer von uns ist richtig?

+0

Können Sie einem IEnumerable eine Zeichenfolge zuweisen? – dcg

+0

Das war ich verflixte das Beispiel, weil Kaffee == null. Festsetzung. – CDove

+0

Bitte korrigieren Sie Ihr Beispiel, um zumindest kompilierbar zu sein? –

Antwort

5

Nein, eigentlich ist es so:

static ClassName() 
{ 
    foo = GetMyStrings(); 
} 

Der Compiler einen statischen Konstruktor erzeugt und stellt die Zuordnung Anruf dort (wie es eine Linie in den Konstruktor für nicht-statische Eigenschaften erzeugt).

Mein Kollege besteht darauf, dies mit einem GC-Problem Risiken, und dass das Ergebnis des GetMyStrings() außerhalb des Bereichs fällt und gesammelt werden „renullifying“ die Parameter und verursachte mehrere Anrufe zu GetMyStrings() über die gesamte Lebensdauer der Objekt.

Er redet Unsinn. Eine zugewiesene Instanz wird niemals Müll gesammelt, unabhängig davon, wo genau sie zugewiesen wurde.

+0

Was ist genug, oder? Die 'statische' Instanz wird niemals fallengelassen und die zugewiesenen statischen Elemente werden nicht gelöscht. –

+0

Danke. Derselbe Kollege hat mir einmal gesagt, dass er Linq nicht benutzt, weil es "noch nicht lange genug ist". Vor 3 Jahren. Ich bekomme heute ein kostenloses Mittagessen. – CDove

+0

LINQ wurde mit C# 3 veröffentlicht, das war 2007. Es ist bereits 10 Jahre alt. Für die meisten Technologien bereits am Ende ihrer Lebensdauer;) @CDove –

0

Schreiben dieses

public static IEnumerable<string> Foo { get; set; } = GetMyStrings(); 

syntaktischer Zucker über diese Erklärung ist

public static IEnumerable<string> Foo { get; set; } 

und ein Zusatz von statischen Konstruktor, der wie folgt aussieht:

static MyClass() { 
    Foo = GetMyStrings(); 
} 

(wenn Sie bereits haben statischer Konstruktor, Foo = GetMyStrings(); Zeile wird implizit hinzugefügt).

Other than that, gibt es keinen Unterschied: once it is time for the class to get initialized wird GetMyStrings() vom Konstruktor aufgerufen, dann wird der Wert wird auf Foo zugewiesen zurückgibt. Danach bleibt der Wert dort, bis er durch einen anderen ersetzt wird oder das Programm endet.

Soweit "der Parameter" renullifying "geht, passiert es nie mit der gleichen Instanz des Klassenobjekts. Sie können mehrere Aufrufe an GetMyStrings() erhalten, wenn die App-Domäne, die die Klasse enthält, entladen wird oder wenn die Klasse in eine andere App-Domäne geladen wird, was aber nichts mit der neuen C# 6-Syntax zu tun hat.

Schließlich, wenn Sie nicht Foo nach dem statischen Konstruktor ändern planen, sollten Sie sie macht schreibgeschützt:

public static IEnumerable<string> Foo { get; } = GetMyStrings(); 
0

meinen Kommentar zu veranschaulichen, in diesem Beispiel aussehen:

public void RunTest() 
{ 
    Test t = new Stackoverflow.Form1.Test(); 
    Console.WriteLine(t.Values.First()); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine(t.Values.First()); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine(t.Values.First()); 

    Console.WriteLine("------"); 
    Console.WriteLine(t.Values2.First()); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine(t.Values2.First()); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine(t.Values2.First()); 

    Console.WriteLine("------"); 
    Console.WriteLine(t.Values3.First()); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine(t.Values3.First()); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine(t.Values3.First()); 
} 

public class Test 
{ 
    public IEnumerable<string> Values { get; set; } = GetValues(); 

    public static IEnumerable<string> GetValues() 
    { 
     List<string> results = new List<string>(); 
     for (int i = 0; i < 10; ++i) 
     { 
      yield return DateTime.UtcNow.AddMinutes(i).ToString(); 
     } 
    } 

    public IEnumerable<string> Values2 { get; set; } = GetValues2(); 

    public static IEnumerable<string> GetValues2() 
    { 
     return GetValues().ToList(); 
    } 

    public IEnumerable<string> Values3 { get; set; } = GetValues().ToList(); 
} 

Die Ausgabe davon ist:

19/04/2017 12:24:25 
19/04/2017 12:24:26 
19/04/2017 12:24:27 
------ 
19/04/2017 12:24:25 
19/04/2017 12:24:25 
19/04/2017 12:24:25 
------ 
19/04/2017 12:24:25 
19/04/2017 12:24:25 
19/04/2017 12:24:25 

Werte: Wie Sie sehen können, der IE Numerable <> von der Methode mit Ausbeute wird jedes Mal ausgewertet werden, wenn Sie es aufrufen.

Werte2: Die Methode gibt eine Liste zurück. Da List IEmnumerable implementiert, geben Sie nur die konkrete Instanz von List zurück (obwohl sie als IEnumerable-Schnittstelle dargestellt wird) und wird daher nur einmal ausgewertet.

Werte3: Wir haben im Grunde die .ToList() außerhalb der GetValues2() -Methode verschoben und nur direkt in der Eigenschaft implementiert. Das Ergebnis ist dasselbe wie Values2, aus dem gleichen Grund.

Wenn Sie ein konkretes Objekt zurückgeben, das IEnumerable implementiert, wird es einmal ausgewertet, aber achten Sie auf das erste Beispiel.

Und denken Sie daran, Leute, Linq ist eine Ansicht. Wenn sich die zugrunde liegenden Daten ändern, ändert sich auch, was von Ihrem Linq-Ausdruck zurückgegeben wird.

Re die Garbage Collection Frage: Objekte, die von einem aktiven Objekt referenziert werden, wird nicht Garbage Collection.

+0

Dies ist eine phänomenale Beweis dafür, wie das funktioniert, um zu gewinnen. – CDove

Verwandte Themen