string s1 = "Ala ma kota"; ref string ref1 = ref s1; ref1 = "Override value"; Console.WriteLine(s1);
Jakie są ograniczenia lokalnych referencji?
- Po pierwsze kompilator nie pozwoli stworzyć referencji do zmiennej, która zostanie usunięta przed referencją (zakres widzialności zmiennej i referencji musi być taki sam).
- Nie można stosować ref dla metod asynchronicznych (async)
- nie można używać w iteratorach
- nie można używać w funkcjach anonimowych
Warto jednak zaznaczyć, że ref można zastosować dla właściwości. Dzieje się tak dlatego, że właściwości są przekształcane do metod get i set. Generalna zasada jest taka, że kompilator musi mieć pewność że referencja nie "przeżyje" obiektu do którego ta referencja się odnosi.
Zobaczmy teraz kilka przykładów:
public class Sample { public ref int WillFail() { int i = 42; return ref i; } }
Kod ten nie skompiluje się gdyż, zmienna i przestanie istnieć po opuszczeniu zasięgu metody WillFail.
public class Sample { public ref int GetSameRef(ref int arg) => ref arg; public ref int WillFail() { int i = 42; return ref GetSameRef(ref i); } }
Kod ten także nie zadziała. Próbujemy poprzez dodatkową funkcję zwrócić referencję do zmiennej i która po opuszczeniu zasięgu metody WillFail zostanie usunięta.
public class Sample { public ref int GetSameRef(ref int arg) => ref arg; public ref int WillWork(ref int i) { return ref GetSameRef(ref i); } }
Ten przypadek zadziała poprawnie. Zwracamy referencję do zmiennej, która zostanie przekazana z zewnątrz a więc "przeżyje" lokalny zasięg.
public class Sample { private int i; private int[] tab = new int[5]; public ref int ReferenceToField => ref i; public ref int ReferenceToArrayElement(int index) => ref tab[index]; }
Powyższy przykład także będzie kompilował się poprawnie - zostanie zwrócona referencja do pola oraz elementu tablicy. Jest to możliwe dlatego, że składowe klasy żyją na stosie i garbage collector jest świadomy, aby ich nie usuwać.
Jaka jest realna zaleta używania ref dla lokalnych zmiennych i wartości zwracanych? Tak samo jak w przypadku przesyłania dużych struktur danych możemy zaoszczędzić moc, która byłaby marnowana na kopiowanie obiektów.
Brak komentarzy:
Prześlij komentarz