Prowadzenie przyjaznej debaty na ten temat ze współpracownikiem. Mamy kilka przemyśleń na ten temat, ale zastanawiamy się, co o tym myśli tłum SO?
c#
immutability
language-design
readonly
Brian Genisio
źródło
źródło
Odpowiedzi:
Jednym z powodów jest brak obsługi środowiska CLR dla lokalnego pliku tylko do odczytu. Tylko do odczytu jest tłumaczone na kod początkowy CLR / CLI. Ta flaga może być stosowana tylko do pól i nie ma znaczenia dla lokalnego. W rzeczywistości zastosowanie go do lokalnego prawdopodobnie spowoduje nieweryfikowalny kod.
Nie oznacza to, że C # nie mógł tego zrobić. Ale dałoby to dwa różne znaczenia tej samej konstrukcji językowej. Wersja dla lokalnych nie miałaby odpowiednika mapowania CLR.
źródło
readonly
kluczowe dla pól musi być obsługiwane przez interfejs wiersza polecenia, ponieważ jego efekt jest widoczny dla innych zestawów. Oznaczałoby to jedynie, że zmienna ma tylko jedno przypisanie w metodzie w czasie kompilacji.const
(co w C ++ bardziej przypomina C #readonly
niż C #const
, chociaż może pełnić obie role). Jednak C ++ obsługujeconst
lokalną zmienną automatyczną. Stąd brak obsługi CLR dla C #readonly
dla zmiennej lokalnej jest nieistotny.using
iout
robią dokładnie to, a świat się nie zawalił.Myślę, że to kiepska ocena ze strony architektów C #. Modyfikator readonly na zmiennych lokalnych pomaga utrzymać poprawność programu (podobnie jak asserts) i może potencjalnie pomóc kompilatorowi w optymalizacji kodu (przynajmniej w przypadku innych języków). Fakt, że jest to obecnie niedozwolone w C #, jest kolejnym argumentem, że niektóre „funkcje” C # są jedynie wymuszeniem osobistego stylu kodowania jego twórców.
źródło
Biorąc pod uwagę odpowiedź Jareda, prawdopodobnie musiałaby to być tylko funkcja kompilacyjna - kompilator zabroniłby zapisywania do zmiennej po początkowej deklaracji (która musiałaby zawierać przypisanie).
Czy widzę w tym wartość? Potencjalnie - ale szczerze mówiąc niewiele. Jeśli nie możesz łatwo stwierdzić, czy zmienna ma zostać przypisana w innym miejscu metody, oznacza to, że Twoja metoda jest za długa.
Co więcej, Java ma tę funkcję (używając
final
modyfikatora) i bardzo rzadko widziałem ją używaną w innych przypadkach niż w przypadkach, w których musi być używana, aby umożliwić przechwytywanie zmiennej przez anonimową klasę wewnętrzną - i gdzie jest używane, sprawia wrażenie raczej bałaganu niż przydatnych informacji.źródło
readonly
/final
wartości od zmiennych za pomocą swoich słów kluczowychval
ivar
. W kodzie Scala, lokalneval
s są używane bardzo często (i faktycznie są preferowane w stosunku do lokalnychvar
). Podejrzewam, że główne powody, dla którychfinal
modyfikator nie jest częściej używany w Javie to a) bałagan i b) lenistwo.readonly
nie byłoby to zbyt ważne. Z drugiej strony, dla zmiennych lokalnych, które są używane w domknięciach,readonly
w wielu przypadkach pozwoliłoby kompilatorowi wygenerować bardziej wydajny kod. Obecnie, gdy wykonanie wchodzi do bloku zawierającego zamknięcie, kompilator musi utworzyć nowy obiekt sterty dla zamkniętych zmiennych, nawet jeśli żaden kod, który używałby zamknięcia, nigdy nie został wykonany . Gdyby zmienna była tylko do odczytu, kod poza zamknięciem mógłby używać zwykłej zmiennej; tylko wtedy, gdy zostanie utworzony delegat na zamknięcie ...Propozycja ustawień lokalnych i parametrów tylko do odczytu została krótko omówiona przez zespół projektowy C # 7. Z notatek ze spotkania projektowego w języku C # z dnia 21 stycznia 2015 r . :
Dyskusja jest kontynuowana w repozytorium projektu języka C #. Głosuj, aby okazać swoje poparcie. https://github.com/dotnet/csharplang/issues/188
źródło
Jest to przeoczenie dla projektanta języka C #. F # ma słowo kluczowe val i jest oparte na środowisku CLR. Nie ma powodu, dla którego C # nie może mieć tej samej funkcji języka.
źródło
Byłem tym współpracownikiem i nie było to przyjazne! (żartuję)
Nie eliminowałbym tej funkcji, ponieważ lepiej jest pisać krótkie metody. To trochę tak, jakbyś powiedział, że nie powinieneś używać wątków, ponieważ są trudne. Daj mi nóż i pozwól mi być odpowiedzialnym za to, że się nie skaleczysz.
Osobiście potrzebowałem innego słowa kluczowego typu „var”, takiego jak „inv” (niezmienny) lub „rvar”, aby uniknąć bałaganu. Uczyłem się F # od późna i uważam, że niezmienna rzecz jest atrakcyjna.
Nigdy nie wiedziałem, że Java to ma.
źródło
Chciałbym lokalnych zmiennych tylko do odczytu w taki sam sposób, jak lubię lokalne zmienne const . Ale ma mniejszy priorytet niż inne tematy.
Być może jego priorytetem jest ten sam powód, dla którego projektanci C # nie wdrożyli (jeszcze!) Tej funkcji. Jednak w przyszłych wersjach obsługa lokalnych zmiennych tylko do odczytu powinno być łatwe (i kompatybilne wstecz).
źródło
Tylko do odczytu oznacza, że jedyne miejsce, w którym można ustawić zmienną instancji, znajduje się w konstruktorze. Podczas deklarowania zmiennej lokalnie nie ma ona instancji (jest tylko w zakresie) i konstruktor nie może jej dotknąć.
źródło
Wiem, to nie odpowiada na twoje pytanie dlaczego. W każdym razie osoby czytające to pytanie mogą mimo wszystko docenić poniższy kod.
Jeśli naprawdę zależy ci na strzelaniu sobie w stopę podczas nadpisywania zmiennej lokalnej, która powinna być ustawiona tylko raz, i nie chcesz, aby była ona bardziej dostępną globalnie, możesz zrobić coś takiego.
Przykładowe użycie:
Może nie tak mniej kodu, jak
rvar rInt = 5
ale działa.źródło
Możesz zadeklarować zmienne lokalne tylko do odczytu w C #, jeśli używasz kompilatora interaktywnego C #
csi
:Możesz także zadeklarować zmienne lokalne tylko do odczytu w
.csx
formacie skryptu.źródło
message
nie jest tutaj zmienną, jest ona skompilowana do pola. To nie jest szukanie dziur w dziury, ponieważ rozróżnienie wyraźnie istnieje również w interaktywnym C #:int x; Console.WriteLine(x)
jest legalnym interaktywnym C # (ponieważx
jest polem i niejawnie zainicjowane), alevoid foo() { int x; Console.WriteLine(x); }
nie jest (ponieważx
jest zmienną i jest używane przed jej przypisaniem). PonadtoExpression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberType
ujawni, żex
jest to naprawdę pole, a nie zmienna lokalna.c # ma już zmienną tylko do odczytu, aczkolwiek w nieco innej składni:
Rozważ następujące kwestie:
Porównać z:
Trzeba przyznać, że pierwszym rozwiązaniem może być mniej kodu do napisania. Ale drugi fragment spowoduje, że odwołanie do zmiennej będzie jawne tylko do odczytu.
źródło
readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");
.użyj
const
słowa kluczowego, aby zmienić tylko do odczytu.odniesienie: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const
źródło
const
którym zmienna może być przypisana tylko podczas jej inicjalizacji, a nie styl csharp, wconst
którym mogą być używane tylko wyrażenia czasu kompilacji. Np. Nie możesz zrobić,const object c = new object();
alereadonly
lokalny by ci na to pozwolił.Myślę, że dzieje się tak dlatego, że funkcja, która ma zmienną tylko do odczytu, może nigdy nie zostać wywołana i prawdopodobnie jest w niej coś, co wykracza poza zakres, a kiedy trzeba?
źródło