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?
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?
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.
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ługuje const
lokalną zmienną automatyczną. Stąd brak obsługi CLR dla C # readonly
dla zmiennej lokalnej jest nieistotny.
using
i out
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.
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.
readonly
/ final
wartości od zmiennych za pomocą swoich słów kluczowych val
i var
. W kodzie Scala, lokalne val
s są używane bardzo często (i faktycznie są preferowane w stosunku do lokalnych var
). Podejrzewam, że główne powody, dla których final
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 . :
Parametry i parametry lokalne mogą być przechwytywane przez lambdy i w ten sposób dostępne jednocześnie, ale nie ma sposobu, aby chronić je przed problemami ze wspólnym stanem: nie można ich tylko do odczytu.
Ogólnie rzecz biorąc, większości parametrów i wielu ustawień lokalnych nigdy nie ma być przypisanych po uzyskaniu ich wartości początkowej. Zezwolenie tylko na odczyt na nich jasno wyraziłoby ten zamiar.
Jednym z problemów jest to, że ta funkcja może być „atrakcyjną uciążliwością”. Podczas gdy „właściwą rzeczą” prawie zawsze byłoby uczynienie parametrów i lokalnych tylko odczytu, spowodowałoby to znaczne zagracenie kodu.
Pomysł, aby częściowo temu zaradzić, polega na umożliwieniu skrócenia kombinacji readonly var do zmiennej lokalnej do wartości val lub czegoś podobnego. Bardziej ogólnie moglibyśmy spróbować po prostu wymyślić krótsze słowo kluczowe niż ustalone tylko do odczytu, aby wyrazić „tylko do odczytu”.
Dyskusja jest kontynuowana w repozytorium projektu języka C #. Głosuj, aby okazać swoje poparcie. https://github.com/dotnet/csharplang/issues/188
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.
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.
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).
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ąć.
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.
public class ReadOnly<T>
{
public T Value { get; private set; }
public ReadOnly(T pValue)
{
Value = pValue;
}
public static bool operator ==(ReadOnly<T> pReadOnlyT, T pT)
{
if (object.ReferenceEquals(pReadOnlyT, null))
{
return object.ReferenceEquals(pT, null);
}
return (pReadOnlyT.Value.Equals(pT));
}
public static bool operator !=(ReadOnly<T> pReadOnlyT, T pT)
{
return !(pReadOnlyT == pT);
}
}
Przykładowe użycie:
var rInt = new ReadOnly<int>(5);
if (rInt == 5)
{
//Int is 5 indeed
}
var copyValueOfInt = rInt.Value;
//rInt.Value = 6; //Doesn't compile, setter is private
Może nie tak mniej kodu, jak rvar rInt = 5
ale działa.
Możesz zadeklarować zmienne lokalne tylko do odczytu w C #, jeśli używasz kompilatora interaktywnego C # csi
:
>"C:\Program Files (x86)\MSBuild\14.0\Bin\csi.exe"
Microsoft (R) Visual C# Interactive Compiler version 1.3.1.60616
Copyright (C) Microsoft Corporation. All rights reserved.
Type "#help" for more information.
> readonly var message = "hello";
> message = "goodbye";
(1,1): error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer)
Możesz także zadeklarować zmienne lokalne tylko do odczytu w .csx
formacie skryptu.
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), ale void foo() { int x; Console.WriteLine(x); }
nie jest (ponieważ x
jest zmienną i jest używane przed jej przypisaniem). Ponadto Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberType
ujawni, że x
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:
var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;
Porównać z:
var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();
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.
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
public class SealedTest
{
static void Main()
{
const int c = 707;
Console.WriteLine("My local constant = {0}", c);
}
}
const
którym zmienna może być przypisana tylko podczas jej inicjalizacji, a nie styl csharp, w const
którym mogą być używane tylko wyrażenia czasu kompilacji. Np. Nie możesz zrobić, const object c = new object();
ale readonly
lokalny by ci na to pozwolił.