Wygląda to dziwnie, szczególnie dla programistów C ++. W C ++ oznaczaliśmy parametr jako const
, aby mieć pewność, że jego stan nie zostanie zmieniony w metodzie. Istnieją również inne specyficzne powody C ++, takie jak przekazywanie const ref
w celu przejścia przez ref i upewnienia się, że stan nie zostanie zmieniony. Ale dlaczego nie możemy oznaczyć jako stałych parametrów metody w C #?
Dlaczego nie mogę zadeklarować mojej metody w następujący sposób?
....
static void TestMethod1(const MyClass val)
{}
....
static void TestMethod2(const int val)
{}
....
c#
language-agnostic
language-design
Incognito
źródło
źródło
Odpowiedzi:
Oprócz innych dobrych odpowiedzi, dodam jeszcze jeden powód, dla którego nie należy umieszczać stałości w stylu C w C #. Powiedziałeś:
Gdyby const faktycznie to zrobił, byłoby świetnie. Const tego nie robi. Stała to kłamstwo!
Const nie daje żadnej gwarancji, że mogę faktycznie użyć. Załóżmy, że masz metodę, która przyjmuje stałą rzecz. Jest dwóch autorów kodu: osoba pisząca dzwoniącego i osoba pisząca adres . Autor wywoływanego obiektu sprawił, że metoda przyjmuje stałą. Co obaj autorzy mogą założyć, że przedmiot jest niezmienny?
Nic. Wywoływany może odrzucić stałą i zmutować obiekt, więc wywołujący nie ma gwarancji, że wywołanie metody, która przyjmuje stałą, w rzeczywistości jej nie zmieni. Podobnie, odbiorca nie może zakładać, że zawartość przedmiotu nie zmieni się podczas działania wywoływanego; wywoływany mógłby wywołać jakąś metodę mutacji na aliasie innym niż const obiektu const, a teraz tak zwany obiekt const uległ zmianie .
Stała w stylu C nie gwarantuje, że obiekt się nie zmieni i dlatego jest zepsuta. Teraz C ma już słaby system typów, w którym możesz dokonać reinterpretacji rzutowania double na int, jeśli naprawdę chcesz, więc nie powinno być zaskoczeniem, że ma słaby system typów również w odniesieniu do const. Ale C # został zaprojektowany, aby mieć dobry system typów, system typów, w którym kiedy mówisz „ta zmienna zawiera ciąg znaków”, zmienna faktycznie zawiera odniesienie do ciągu (lub wartości null). Absolutnie nie chcemy umieszczać modyfikatora "const" w stylu C w systemie typów, ponieważ nie chcemy, aby system typów był kłamstwem . Chcemy, aby system typów był mocny , abyś mógł poprawnie uzasadnić swój kod.
Const w C to wskazówka ; w zasadzie oznacza to „możesz mi zaufać, że nie będę próbował tego modyfikować”. To nie powinno być w systemie typów ; rzeczy w systemie typów powinny być faktem o obiekcie, co do którego można uzasadnić, a nie wskazówką dotyczącą jego użycia.
Nie zrozum mnie źle; tylko dlatego, że const w C jest głęboko zerwane, nie oznacza, że cała koncepcja jest bezużyteczna. To, co chciałbym zobaczyć, to rzeczywiście poprawna i użyteczna forma adnotacji „const” w C #, adnotacja, której zarówno ludzie, jak i kompilatorzy mogliby użyć, aby pomóc im zrozumieć kod, i której środowisko wykonawcze mogłoby użyć do takich rzeczy, jak automatyczna paralelizacja i inne zaawansowane optymalizacje.
Na przykład, wyobraź sobie, że możesz „narysować prostokąt” wokół kawałka kodu i powiedzieć „ Gwarantuję, że ten fragment kodu nie wykona mutacji w żadnym polu tej klasy” w sposób, który mógłby zostać sprawdzony przez kompilator. Lub narysuj ramkę, która mówi: „ta czysta metoda zmienia stan wewnętrzny obiektu, ale w żaden sposób nie jest obserwowalny poza ramką”. Taki obiekt nie mógł być bezpiecznie wielowątkowy automatycznie, ale mógłby zostać automatycznie zapamiętany . Istnieje wiele interesujących adnotacji, które moglibyśmy umieścić w kodzie, które umożliwiłyby rozbudowane optymalizacje i głębsze zrozumienie. Możemy zrobić o wiele lepiej niż słaba adnotacja const w stylu C.
Podkreślam jednak, że to tylko spekulacje . Nie mamy konkretnych planów umieszczenia tego rodzaju funkcji w żadnej hipotetycznej przyszłej wersji C #, jeśli w ogóle istnieje, której nie ogłosiliśmy w taki czy inny sposób. Jest to coś, co chciałbym zobaczyć i coś, czego może wymagać nadchodzący nacisk na przetwarzanie wielordzeniowe, ale nic z tego nie powinno być w żaden sposób interpretowane jako przewidywanie lub gwarancja jakiejkolwiek konkretnej funkcji lub przyszłego kierunku C #.
Teraz, jeśli chcesz tylko adnotacji na zmiennej lokalnej, która jest parametrem, który mówi, że „wartość tego parametru nie zmienia się w całej metodzie”, to z pewnością byłoby to łatwe. Moglibyśmy obsługiwać ustawienia lokalne i parametry „tylko do odczytu”, które byłyby inicjowane raz, oraz błąd kompilacji w czasie zmiany metody. Zmienna zadeklarowana przez instrukcję „using” jest już taką lokalną; moglibyśmy dodać opcjonalną adnotację do wszystkich lokalnych i parametrów, aby zachowywały się jak „używanie” zmiennych. Nigdy nie była to funkcja o wysokim priorytecie, więc nigdy nie została zaimplementowana.
źródło
0xDEADBEEF
. Ale oba byłyby bardzo złym programowaniem i wcześnie i przejmująco złapane przez każdy nowoczesny kompilator. W przyszłości podczas pisania odpowiedzi nie myl tego, co jest technicznie możliwe przy użyciu backdoorów języka z tym, co jest wykonalne w rzeczywistym kodzie świata. Takie wypaczone informacje dezorientują mniej doświadczonych czytelników i obniżają jakość informacji o SO.Jednym z powodów, dla których nie ma poprawności stałej w C #, jest to, że nie istnieje na poziomie środowiska uruchomieniowego. Pamiętaj, że C # 1.0 nie miał żadnej funkcji, chyba że była częścią środowiska uruchomieniowego.
A kilka powodów, dla których CLR nie ma pojęcia stałej poprawności, to na przykład:
Stała poprawność jest w zasadzie cechą języka obecną tylko w C ++. Tak więc w zasadzie sprowadza się to do tej samej argumentacji, dlaczego CLR nie wymaga sprawdzonych wyjątków (jest to funkcja dostępna tylko w języku Java).
Nie sądzę również, aby można było wprowadzić tak podstawową funkcję systemu typów w zarządzanym środowisku bez zerwania wstecznej kompatybilności. Więc nie licz na stałą poprawność, która kiedykolwiek wejdzie do świata C #.
źródło
ref
parametru (szczególnie w przypadku metod / właściwości strukturythis
). Jeśli metoda wyraźnie stwierdza, że nie będzie zapisywać doref
parametru, kompilator powinien zezwolić na przekazywanie wartości tylko do odczytu. I odwrotnie, jeśli metoda stwierdza, że będzie zapisywaćthis
, kompilator nie powinien zezwalać na wywoływanie takiej metody na wartościach tylko do odczytu.Uważam, że istnieją dwa powody, dla których C # nie jest stała.
Pierwsza to zrozumiałość . Niewielu programistów C ++ rozumie stałą poprawność. Prosty przykład
const int arg
jest ładny, ale widziałem teżchar * const * const arg
- stały wskaźnik do stałych wskaźników do niestałych znaków. Stała poprawność wskaźników do funkcji to zupełnie nowy poziom zaciemniania.Po drugie, argumenty klas są referencjami przekazywanymi przez wartość. Oznacza to, że mamy już do czynienia z dwoma poziomami stałości, bez oczywiście jasnej składni . Podobnym punktem potknięcia są kolekcje (i zbiory kolekcji itp.).
Stała poprawność jest ważną częścią systemu typów C ++. Mógłby - teoretycznie - zostać dodany do C # jako coś, co jest sprawdzane tylko w czasie kompilacji (nie musi być dodawane do CLR i nie wpłynie na BCL, chyba że uwzględniono pojęcie stałych metod składowych) .
Uważam jednak, że jest to mało prawdopodobne: druga przyczyna (składnia) byłaby dość trudna do rozwiązania, co sprawiłoby, że pierwsza przyczyna (zrozumiałość) byłaby jeszcze większym problemem.
źródło
modopt
imodreq
na poziomie metadanych do przechowywania tych informacji (jak C + / CLI już to robi - zobaczSystem.Runtime.CompilerServices.IsConst
); i to można by w trywialny sposób rozszerzyć na metody const.const
oznacza „stałą czasu kompilacji” w C #, a nie „tylko do odczytu, ale prawdopodobnie modyfikowalną przez inny kod”, jak w C ++. Z grubsza analog C ++const
w C # jestreadonly
, ale ten ma zastosowanie tylko do pól. Poza tym, w C # nie ma żadnego podobnego do C ++ pojęcia poprawności const.Trudno powiedzieć na pewno, ponieważ potencjalnych powodów jest wiele, ale przypuszczam, że byłby to przede wszystkim chęć zachowania prostego języka i niepewne korzyści z wdrożenia tego drugiego.
źródło
Jest to możliwe od wersji C # 7.2 (grudzień 2017 z programem Visual Studio 2017 15.5).
Tylko dla struktur i typów podstawowych !, nie dla członków klas.
Musisz użyć
in
aby wysłać argument jako dane wejściowe przez odwołanie. Widzieć:Widzieć: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier
Na przykład:
źródło