Po pierwsze, odpowiedzi Jona, Michaela i Jareda są zasadniczo poprawne, ale mam jeszcze kilka rzeczy, które chciałbym do nich dodać.
Co należy rozumieć pod pojęciem „nieczystej” metody?
Łatwiej jest scharakteryzować czyste metody. „Czysta” metoda ma następujące cechy:
- Jego wynik jest całkowicie określony przez jego dane wejściowe; jego wydajność nie zależy od czynników zewnętrznych, takich jak pora dnia lub ilość bitów na dysku twardym. Jej dorobek nie zależy od historii; dwukrotne wywołanie metody z podanym argumentem powinno dać ten sam wynik.
- Czysta metoda nie powoduje żadnych obserwowalnych mutacji w otaczającym ją świecie. Czysta metoda może zdecydować się na mutację stanu prywatnego ze względu na efektywność, ale czysta metoda nie zmienia, powiedzmy, pola swojego argumentu.
Na przykład Math.Cos
to czysta metoda. Jego wyjście zależy tylko od jego wejścia, a wejście nie jest zmieniane przez wywołanie.
Nieczysta metoda to metoda, która nie jest czysta.
Jakie są niebezpieczeństwa związane z przekazywaniem struktur tylko do odczytu do nieczystych metod?
Przychodzą mi do głowy dwie. Pierwszą jest ta wskazana przez Jona, Michaela i Jareda i przed nią ostrzega cię Resharper. Kiedy wywołujesz metodę na strukturze, zawsze przekazujemy odniesienie do zmiennej, która jest odbiornikiem, na wypadek gdyby metoda chciała zmutować zmienną.
A co, jeśli wywołasz taką metodę na wartości, a nie na zmiennej? W takim przypadku tworzymy zmienną tymczasową, kopiujemy do niej wartość i przekazujemy referencję do zmiennej.
Zmienna tylko do odczytu jest uważana za wartość, ponieważ nie można jej mutować poza konstruktorem. Więc kopiujemy zmienną do innej zmiennej, a nieczysta metoda prawdopodobnie powoduje mutację kopii, jeśli zamierzasz zmutować zmienną.
Na tym polega niebezpieczeństwo przekazania struktury tylko do odczytu jako odbiorcy . Istnieje również niebezpieczeństwo przekazania struktury zawierającej pole tylko do odczytu. Struktura zawierająca pole tylko do odczytu jest powszechną praktyką, ale zasadniczo polega ona na wypisywaniu czeku, że system typów nie ma środków do zrealizowania; „Tylko do odczytu” konkretnej zmiennej określa właściciel magazynu. Instancja typu referencyjnego „posiada” własną pamięć, ale instancja typu wartościowego nie!
struct S
{
private readonly int x;
public S(int x) { this.x = x; }
public void Badness(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
Console.WriteLine(this.x);
}
}
Wydaje się, że this.x
to się nie zmieni, ponieważ x jest polem tylko do odczytu i Badness
nie jest konstruktorem. Ale...
S s = new S(1);
s.Badness(ref s);
... jasno pokazuje, że to fałsz. this
i s
odnoszą się do tej samej zmiennej, a ta zmienna nie jest tylko do odczytu!