Zrozumienie zmiennych i typów danych w C#
W programowaniu w języku C# zmienne są podstawowymi elementami służącymi do przechowywania wartości danych. Zrozumienie, jak skutecznie definiować i używać zmiennych, ma kluczowe znaczenie dla pisania wydajnego i łatwego w utrzymaniu kodu. Zmienne mogą być różnych typów, w tym typów danych podstawowych, stałych i zmiennych typowanych dynamicznie, z których każda służy określonym celom. Dodatkowo, konwersja typów, dynamic, i var słowa kluczowe dodają elastyczność i odporność do programowania w C#.
Film Tima Coreya pt. "Dynamic vs Var w C#" zawiera kompleksowy przegląd tych pojęć. W tym artykułe omówimy kilka tematów poruszonych przez Tima, w tym:
- Różnica między Dynamic a Var
- Podstawowe typy danych
- Zmienne i stałe
- Dynamiczna automatyczna konwersja typów
- Wady dynamiki w rozwoju
- Dłączego i kiedy używać Dynamic
- Dłączego i kiedy używać Var
Dzięki zrozumieniu tych pojęć dzięki wyjaśnieniom Tima Coreya zyskasz głębszy wgląd w to, jak skutecznie zarządzać zmiennymi w języku C# i wykorzystywać je.
Różnica między Dynamic a Var
W C#, var jest używane dla lokalnych zmiennych o niejawnie przypisanym typie, gdzie typ jest określany w czasie kompilacji, zapewniając bezpieczeństwo typów i wsparcie IntelliSense. Dla kontrastu, dynamic pozwala zmiennym obejść sprawdzanie typu w czasie kompilacji, z typem rozpoznawanym w czasie wykonania, oferując większą elastyczność, ale z ryzykiem błędów w czasie wykonania i zmniejszoną wydajnością.
Tim Corey wyjaśnia, że var zapewnia bezpieczeństwo typów dzięki określeniu typu w czasie kompilacji, jako że są to zmienne statyczne, podczas gdy dynamic oferuje elastyczność dzięki rozpoznawaniu typu w czasie wykonania, co może prowadzić do błędów i problemów z wydajnością.
Podstawowe typy danych
Tim rozpoczyna swoją prezentację w Visual Studio od przedstawienia podstawowych typów danych w języku C#. Tworzy obiekt dynamic nazwany testDynamic, który może otrzymać nową wartość w dowolnym momencie, a jego typ danych może się dynamicznie zmieniać w czasie wykonania. Jest to pokazane w następującym kodzie:
// Declaration of a dynamic variable that can change types at runtime
dynamic testDynamic;
// Declaration of a dynamic variable that can change types at runtime
dynamic testDynamic;
Język C# udostępnia kilka podstawowych typów danych do obsługi różnego rodzaju danych. Typy całkowitoliczbowe obejmują int dla 32-bitowych liczb całkowitych ze znakiem, long dla 64-bitowych liczb całkowitych ze znakiem, short dla 16-bitowych liczb całkowitych ze znakiem, oraz byte dla 8-bitowych liczb całkowitych bez znaku. Dla liczb zmiennoprzecinkowych, C# oferuje float dla wartości pojedynczej precyzji 32-bitowej, double dla wartości podwójnej precyzji 64-bitowej, oraz decimal dla 128-bitowych precyzyjnych wartości dziesiętnych, idealne dla obliczeń finansowych. Typ danych char reprezentuje 16-bitowe znaki Unicode, podczas gdy typ bool jest używany dla wartości prawdziwej lub fałszywej. Dodatkowo, typ danych string reprezentuje ciąg znaków, umożliwiając przechowywanie i manipulację tekstem.
Te typy danych mają fundamentalne znaczenie dla programowania w języku C#, umożliwiając wydajne przechowywanie i przetwarzanie danych, co Tim pokazuje w kolejnych przykładach. Wiele zmiennych można zadeklarować i przypisać integralne typy int na jednej linii, a każdy typ danych ma wartość domyślną, jeśli nie jest wyraźnie przypisany wartością początkową. Zmienne stałe zachowują stałe wartości, zapewniając spójność w całym kodzie. Ponadto za pomocą tych typów danych można również deklarować zmienne instancji i zmienne statyczne, co zapewnia solidną i elastyczną strukturę programów.
Zmienne i stałe
Tim Corey o 1:21 próbuje stworzyć obiekt var nazwany testVar bez początkowego przypisania, co prowadzi do błędu w czasie kompilacji, ponieważ var wymaga początkowego przypisania do określenia typu:
// This will result in a compile-time error due to lack of type inference
// var testVar;
// This will result in a compile-time error due to lack of type inference
// var testVar;
To skutkuje czerwoną podkreśloną linią pod testVar, wskazującą na błąd. O 1:55 Tim wyjaśnia, że var musi być przypisany typ podczas deklaracji. Na przykład:
// var assignment with type inference from the initial value
var testVar = 2; // testVar is inferred to be of type int
// var assignment with type inference from the initial value
var testVar = 2; // testVar is inferred to be of type int
Tim (2:44) demonstruje, że jeśli później spróbuje przypisać wartość typu double do testVar, powoduje to błąd, ponieważ testVar pierwotnie przypisano jako int:
// Attempting to change the type from int to double causes an error
// testVar = 1.1; // Error: Cannot implicitly convert type 'double' to 'int'
// Attempting to change the type from int to double causes an error
// testVar = 1.1; // Error: Cannot implicitly convert type 'double' to 'int'
Tim (3:17) podkreśla, że typ var jest ustalony w momencie jego początkowego przypisania i nie może się zmienić później. Jeśli testVar jest pierwotnie przypisany wartością typu double, zostanie określony jako double:
// Another example with dynamic typing
var testVar = 2.1; // Now testVar is a double
// Another example with dynamic typing
var testVar = 2.1; // Now testVar is a double
Chociaż Tim nie porusza tematu zmiennych stałych, są one równie ważne w programach napisanych w języku C#. Stałe w C# są deklarowane za pomocą słowa kluczowego const, po którym następuje typ danych i identyfikator zmiennej stałej, jak:
// Declaring a constant variable
const int MaxValue = 100;
// Declaring a constant variable
const int MaxValue = 100;
Stałym należy przypisać wartość w momencie deklaracji, której nie można zmienić podczas wykonywania programu, zapewniając niezmienne wartości dla logiki programu.
Dynamiczna automatyczna konwersja typów
Tim podkreśla, w jaki sposób słowo kluczowe dynamic pozwala na elastyczne zarządzanie typami, działając nieco jak object, ale z dodatkowymi możliwościami. O 3:53, Tim demonstruje, jak dynamic może płynnie konwertować się między różnymi typami podczas wykonania, pokazując swoją zdolność do obsługi obliczeń z udziałem liczb całkowitych i wartości typu double bez jawnego rzutowania, jak pokazano w jego przykładzie kodu:
// Demonstrating dynamic type conversion at runtime
dynamic testDynamic = 1;
testDynamic = testDynamic + 2.1;
Console.WriteLine(testDynamic); // Outputs 3.1 as it converts the integer to a double
// Demonstrating dynamic type conversion at runtime
dynamic testDynamic = 1;
testDynamic = testDynamic + 2.1;
Console.WriteLine(testDynamic); // Outputs 3.1 as it converts the integer to a double
Tutaj, Tim (4:39) ilustruje, że testDynamic początkowo przechowuje wartość całkowitą, ale bez problemu konwertuje ją na wartość typu double, kiedy dodaje do niej 2.1, dając w wyniku 3.1.
Pomimo swojej elastyczności, Tim ostrzega przed nadużywaniem dynamic z powodu kosztów wydajności wynikających z częstych konwersji typów. Podkreśla o 5:55, że dynamic powinno być używane oszczędnie w rozwoju C#, aby uniknąć niepotrzebnego obciążenia procesora i utraty sprawdzania typów w czasie kompilacji oraz wsparcia IntelliSense, co jest kluczowe dla utrzymania solidnych i bezbłędnych baz kodu.
Wady Dynamic in Development
Tim Corey ilustruje, jak dynamic może prowadzić do błędów w czasie wykonania i nieprzewidzianego zachowania w twoich aplikacjach. Zaczyna od pokazania, jak zadeklarować zmienną dynamiczną i przypisać jej początkowo pusty ciąg znaków, aby uniknąć natychmiastowego błędu. Następnie próbuje wywołać nieistniejącą metodę sayHi na dynamicznej zmiennej, co nie powoduje błędu w czasie kompilacji, ale skutkuje wyjątkiem w czasie wykonania, pokazując kluczową wadę dynamic: brak sprawdzania w czasie kompilacji.
// Demonstrating lack of compile-time checks with dynamic
dynamic testDynamic = "";
// testDynamic.sayHi(); // Runtime error: method does not exist
// Demonstrating lack of compile-time checks with dynamic
dynamic testDynamic = "";
// testDynamic.sayHi(); // Runtime error: method does not exist
Ponadto o godz. 8:38 Tim pokazuje, w jaki sposób zmienne dynamiczne mogą zmieniać typy w czasie wykonywania, co może powodować nieoczekiwane zachowanie. Przypisuje obiekt Person do dynamicznej zmiennej, następnie przypisuje go ponownie do łańcucha znaków i pokazuje, jak taka elastyczność może prowadzić do błędów logicznych i utrudniać debugowanie.
// Demonstrating the potential errors with dynamic type reassignment
dynamic testDynamic = new Person();
testDynamic = "Hi";
Console.WriteLine(testDynamic); // Works fine, but not ideal for type safety
// Demonstrating the potential errors with dynamic type reassignment
dynamic testDynamic = new Person();
testDynamic = "Hi";
Console.WriteLine(testDynamic); // Works fine, but not ideal for type safety
Tim wyjaśnia również, że zmienne dynamiczne nie są obsługiwane przez IntelliSense, co może prowadzić do błędów wykonania spowodowanych literówkami lub nieprawidłowymi nazwami metod. Na przykład o 14:05, wywołuje nazwę właściwości Email, która nie istnieje, podkreślając, jak ten błąd pozostaje niezauważony do momentu wykonania. Kod kompiluje się bez błędów, ale zawodzi w czasie wykonania, kiedy oczekiwane metody lub właściwości na obiekcie Person nie są znalezione na łańcuchu znaków.
// Demonstrating a runtime error due to missing property
// testDynamic.Email = "Test@test.com"; // property not found until runtime
// Demonstrating a runtime error due to missing property
// testDynamic.Email = "Test@test.com"; // property not found until runtime
Zalety używania słowa kluczowego Var
Dla odmiany, var jest mocno typowany i zapewnia sprawdzanie typów w czasie kompilacji oraz wsparcie IntelliSense. Dzięki temu wszelkie problemy związane z typami danych są wykrywane na etapie tworzenia oprogramowania, co sprawia, że kod jest bardziej niezawodny i łatwiejszy w utrzymaniu. Tim Corey demonstruje to, tworząc zmienną var i przypisując do niej obiekt Person:
// Using var for strongly-typed assignments
var testVar = new Person();
testVar.FirstName = "Sue";
testVar.LastName = "Storm";
// The use of IntelliSense assists in reducing runtime errors
Console.WriteLine(testVar.SayHello()); // Ideally a method in Person class
// Using var for strongly-typed assignments
var testVar = new Person();
testVar.FirstName = "Sue";
testVar.LastName = "Storm";
// The use of IntelliSense assists in reducing runtime errors
Console.WriteLine(testVar.SayHello()); // Ideally a method in Person class
Próba wywołania nieistniejącej metody lub ponownego przypisania zmiennej var do innego typu zostanie wychwycona w czasie kompilacji, zapobiegając potencjalnym błędom w czasie wykonania.
// Attempting to change type results in compile-time errors with var
// testVar = "Hi"; // Compile-time error
// Attempting to change type results in compile-time errors with var
// testVar = "Hi"; // Compile-time error
Typ zwracanej wartości metody
O 15:05, Tim demonstruje, że można także zwrócić typ dynamic z metody, ale nie można zwrócić var. Na przykład:
// Method returning a dynamic type
public dynamic GetMessage() {
return "This is a test";
}
// Method returning a dynamic type
public dynamic GetMessage() {
return "This is a test";
}
Próba zwrócenia var spowoduje błąd w czasie kompilacji, ponieważ sygnatura metody musi określać konkretny typ zwracany.
Dłączego i kiedy używać Dynamic
Tim elaboruje scenariusze, w których dynamic staje się niezbędne. Wyjaśnia on, że C# jest zasadniczo językiem silnie typowanym, co oznacza, że każdej zmiennej przypisany jest określony typ, który pozostaje niezmienny przez cały jej cykl życia. Stanowi to kontrast w stosunku do języków takich jak JavaScript, w których zmienne mogą dynamicznie zmieniać typy.
Tim, o godz. 18:14, wyjaśnia, że chociaż język C# jest zaprojektowany z myślą o zmiennych silnie typowanych, istnieją sytuacje, zwłaszcza podczas interakcji z systemami zewnętrznymi lub językami takimi jak Python, Ruby lub obiektami COM, w których typowanie dynamiczne może być korzystne. Używa przykładu integracji z API Python, aby podkreślić praktyczną potrzebę dynamic. W takich przypadkach posiadanie elastycznego systemu typów, który może dostosować się do różnych typów danych z zewnętrznych źródeł, upraszcza interakcję.
Tim Corey o 18:44 podkreśla, że chociaż dynamic jest przydatne dla interakcji między językami, nie jest ogólnie zalecane dla czystego kodu C# ze względu na utratę sprawdzania błędów w czasie kompilacji i wsparcia IntelliSense. Ostrzega, że elastyczność dynamic odbywa się kosztem wydajności i bezpieczeństwa typów, co czyni ją mniej pożądanym wyborem dla regularnego programowania w C#, gdzie preferowane powinny być zmienne mocno typowane.
Dłączego i kiedy używać słowa kluczowego Var
Tim następnie omawia użycie i filozofię stojącą za słowem kluczowym var w C#. Zauważa, że są dwa główne obozy, jeśli chodzi o użycie var: ci, którzy wolą używać go wyłącznie i ci, którzy preferują jawne deklaracje typów.
Tim, o 19:43, wyjaśnia, że zwolennicy var argumentują, że zachęca to do lepszych konwencji nazw, czyniąc kod samodokumentującym się. Uważają oni, że nazwy zmiennych powinny być na tyle opisowe, aby przekazywały typ bez konieczności wyraźnej deklaracji.
Z drugiej strony (20:46) zwolennicy jawnych deklaracji typów argumentują, że widoczność rzeczywistego typu bezpośrednio w kodzie pozwala od razu rozpoznać, jaki jest typ zmiennej lokalnej, bez konieczności najeżdżania kursorem na zmienną w celu sprawdzenia jej typu. Na przykład:
// Explicit type declaration provides clarity
string firstName = "Tim";
// Explicit type declaration provides clarity
string firstName = "Tim";
Jest to preferowane przez niektórych, ponieważ usuwa wszelkie wątpliwości co do typu zmiennej.
Tim dzieli się swoim zrównoważonym podejściem o 21:15, stwierdzając, że zazwyczaj używa jawnych typów dla powszechnych typów danych, takich jak string, int, double i decimal, ponieważ czyni to kod jaśniejszym i unika potencjalnych problemów, takich jak mylenie double i decimal. Na przykład:
// Explicit type ensures there's no ambiguity between float types
double myMoney = 1.1; // This is a double
decimal myMoney = 1.1M; // This is a decimal
// Explicit type ensures there's no ambiguity between float types
double myMoney = 1.1; // This is a double
decimal myMoney = 1.1M; // This is a decimal
Tim podkreśla, że jawne deklarowanie typu zapewnia użycie właściwego typu, zwłaszcza gdy może dojść do zamieszania między podobnymi typami.
Jednak Tim również przyznaje, że var może być szczególnie użyteczne przy pracy z długimi lub złożonymi typami. Przykład podaje o 23:37, gdzie deklarowanie List<List<Person>> może być rozwlekłe:
// Declaring a complex type using var
var rounds = new List<List<Person>>();
// Declaring a complex type using var
var rounds = new List<List<Person>>();
Demonstruje również jego przydatność w pętlach @@--CODE-124@@ (23:55):
// Utilizing var in loop for cleaner code
foreach (var round in rounds) {
// Do something with each round
}
// Utilizing var in loop for cleaner code
foreach (var round in rounds) {
// Do something with each round
}
Tim konkluduje, zauważając, że chociaż var może zmniejszyć rozwlekłość, kluczowe jest zapewnienie, że nazwy zmiennych są jasne i opisowe, aby utrzymać czytelność i unikać zamieszania.
Równoważąc użycie var z jawnymi typami, programiści mogą pisać jasny, utrzymywalny i efektywny kod, wykorzystując mocne strony obu podejść, odpowiednio do kontekstu.
Var jako anonimowy obiekt
Tim omawia użycie var dla sytuacji, gdy typ nie jest jawnie znany lub podczas pracy z anonimowymi typami. Demonstruje to, tworząc anonimowy obiekt na bieżąco, który nie ma wstępnie zdefiniowanego typu. Oto kod, którego używa:
// Creating an anonymous object with var
var myItem = new { FirstName = "Tim", Email = "test@test.com" };
// Creating an anonymous object with var
var myItem = new { FirstName = "Tim", Email = "test@test.com" };
Tim, o 25:30, wyjaśnia, że ponieważ ten obiekt jest anonimowy i nie ma określonej nazwy typu, jedynym sposobem na zadeklarowanie dla niego zmiennych jest użycie var. To podejście pozwala na tworzenie i używanie obiektów bez potrzeby definiowania formalnej klasy.
Aby zilustrować, jak to działa w praktyce, Tim pisze (25:52):
// Outputting properties of an anonymous object
Console.WriteLine($"Hello {myItem.FirstName}: your email is {myItem.Email}");
// Outputting properties of an anonymous object
Console.WriteLine($"Hello {myItem.FirstName}: your email is {myItem.Email}");
Kiedy uruchamia kod o 26:25, wyjściem jest:
To pokazuje, że var może obsłużyć właściwości anonimowego obiektu, a Visual Studio dostarcza wsparcie IntelliSense dla tych właściwości, mimo że obiekt jest anonimowy.
Tim, o 26:54, wyjaśnia, że preferuje użycie jawnych typów dla prostych i powszechnych typów, takich jak string, liczby całkowite i instancje klas, ponieważ czyni to kod jaśniejszym. Jednak używa var w przypadkach, gdy typ jest długi, złożony lub nie jest jawnie znany, na przykład z typami anonimowymi lub złożonymi deklaracjami typów.
Wnioski
I tak mamy — jasne zrozumienie zmiennych i typów danych w C#, wraz ze strategicznym wykorzystaniem słów kluczowych var i dynamic. Postępując zgodnie ze zrównoważonym podejściem Tima Coreya, można zapewnić bezpieczeństwo typów i czytelność w swoim kodzie za pomocą słowa kluczowego var, jednocześnie wykorzystując elastyczność słowa kluczowego dynamic dla specyficznych scenariuszy, takich jak interakcje z zewnętrznymi systemami.
Aby uzyskać bardziej szczegółowe informacje, koniecznie obejrzyj wideo Tima Coreya na temat "Dynamic vs Var in C#" i sprawdź jego kanał YouTube po dalsze tematy związane z nauką C#.



