Celem stałej poprawności jest zapewnienie widoku instancji, której użytkownik nie może zmienić ani usunąć. Kompilator obsługuje to, wskazując, kiedy przerywasz stałość z poziomu funkcji stałej lub próbujesz użyć funkcji innej niż stała obiektu const. Więc bez kopiowania podejścia const, czy istnieje metodologia, której mogę użyć w C #, która ma te same końce?
Zdaję sobie sprawę z niezmienności, ale tak naprawdę nie przenosi się to na obiekty kontenera, by wymienić tylko jeden przykład.
c#
theory
const-correctness
tenpn
źródło
źródło
const_cast
w C #?Odpowiedzi:
Trafiłem też na ten problem wiele razy i skończyło się na korzystaniu z interfejsów.
Myślę, że ważne jest, aby porzucić pomysł, że C # jest dowolną formą, a nawet ewolucją C ++. To dwa różne języki, które mają prawie taką samą składnię.
Zwykle wyrażam `` stałą poprawność '' w C #, definiując widok klasy tylko do odczytu:
public interface IReadOnlyCustomer { String Name { get; } int Age { get; } } public class Customer : IReadOnlyCustomer { private string m_name; private int m_age; public string Name { get { return m_name; } set { m_name = value; } } public int Age { get { return m_age; } set { m_age = value; } } }
źródło
const
, bez dodatkowych kosztów definiowania oddzielnego interfejsu i wymagającego wysłania w czasie wykonywania. Oznacza to, że język zapewnia prosty sposób implementacji interfejsów stałych w czasie kompilacji.const
-ness jest częścią projektu i deklaruje intencję tak samo wyraźnie, jak pisanie zewnętrznego interfejsu const. Ponadto dostarczanie interfejsów stałych może być złożonym zadaniem, jeśli musi być wykonywane ręcznie, i może wymagać napisania prawie tylu interfejsów, ile klas jest obecnych w typie złożonym. To prowadzi nas do twojego ostatniego zdania: „schrzań wszystko, bo zapomniałeś dodać const”. Łatwiej jest przyzwyczaić się do dodawaniaconst
wszędzie (koszt rozwoju jest niewielki) niż do pisania interfejsów tylko do odczytu dla każdej klasy.Aby skorzystać z zalet const-szaleństwa (lub czystości w kategoriach programowania funkcjonalnego), będziesz musiał zaprojektować swoje klasy w taki sposób, aby były niezmienne, tak jak klasa String języka c #.
Takie podejście jest o wiele lepsze niż zwykłe oznaczanie obiektu jako tylko do odczytu, ponieważ dzięki niezmiennym klasom można łatwo przekazywać dane w środowiskach wielozadaniowych.
źródło
Builder
klas dla dużych typów niezmiennych (Java i .NET definiująStringBuilder
klasę, co jest tylko jednym przykładem).Chciałem tylko zauważyć, że wiele kontenerów System.Collections.Generics ma metodę AsReadOnly, która zwraca niezmienną kolekcję.
źródło
C # nie ma takiej funkcji. Możesz przekazać argument według wartości lub przez odwołanie. Samo odwołanie jest niezmienne, chyba że określisz modyfikator ref . Ale dane, do których istnieją odniesienia, nie są niezmienne. Musisz więc uważać, jeśli chcesz uniknąć skutków ubocznych.
MSDN:
Przekazywanie parametrów
źródło
Rozwiązaniem są interfejsy, które w rzeczywistości mają większe możliwości niż „const” w C ++. const to uniwersalne rozwiązanie problemu, w którym „stała” jest zdefiniowana jako „nie ustawia elementów ani nie wywołuje czegoś, co ustawia elementy”. To dobry skrót na określenie ciągłości w wielu scenariuszach, ale nie we wszystkich. Na przykład rozważmy funkcję, która oblicza wartość na podstawie niektórych elementów członkowskich, ale także buforuje wyniki. W C ++ jest to uważane za niestałe, chociaż z punktu widzenia użytkownika jest to zasadniczo stała.
Interfejsy zapewniają większą elastyczność w definiowaniu określonego podzbioru możliwości, które chcesz udostępnić w swojej klasie. Chcesz być konsekwentny? Po prostu zapewnij interfejs bez metod mutowania. Chcesz zezwolić na ustawienie niektórych rzeczy, a innych nie? Zapewnij interfejs tylko z tymi metodami.
źródło
mutable
.Zgadzam się z niektórymi innymi, rozważ użycie pól tylko do odczytu, które zainicjujesz w konstruktorze, aby utworzyć niezmienne obiekty.
public class Customer { private readonly string m_name; private readonly int m_age; public Customer(string name, int age) { m_name = name; m_age = age; } public string Name { get { return m_name; } } public int Age { get { return m_age; } } }
Alternatywnie możesz również dodać zakres dostępu do właściwości, tj. Publiczny zestaw get i protected?
public class Customer { private string m_name; private int m_age; protected Customer() {} public Customer(string name, int age) { m_name = name; m_age = age; } public string Name { get { return m_name; } protected set { m_name = value; } } public int Age { get { return m_age; } protected set { m_age = value; } } }
źródło
Problem z readonly polega na tym, że pozwala on tylko na stałe odniesienie (wskaźnik). Rzecz, do której się odwołuje (wskazywana) może być nadal modyfikowana. To jest trudna część, ale nie da się tego obejść. Zaimplementowanie stałych obiektów oznacza, że nie ujawniają one żadnych modyfikowalnych metod ani właściwości, ale jest to niewygodne.
Zobacz także Efektywny C #: 50 konkretnych sposobów ulepszania języka C # (pozycja 2 - Preferuj tylko do odczytu do stałej).
źródło