यदि हम मोटे तौर पर देखें तो C Language का Program, Functions व Data Types का समूह होता है। C++ का Program, Functions व Classes का समूह होता है। जबकि C# का Program, Type Declarations का समूह होता है।
एक C# Program का .EXE या .DLL वास्तव में एक या एक से ज्यादा Type Declarations का समूह होता है। जबकि एक Executable C# Program में कम से कम एक ऐसा Class Type होता है, जिसमें Main(), DllMain() या WinMain() Method Defined किया गया होता है। इसी तरह से namespace एक ऐसा तरीका है, जिसका प्रयोग करके समान प्रकार के Type Declarations को Group किया जाता है और उस Group of Types का एक नाम Specify कर दिया जाता है।
अत: यदि सरल शब्दों में कहें तो हमारा हर C# Program एक प्रकार का Related Type Declarations का समूह होता है, जिसे हम हमारे Create किए जाने वाले Namespace के बीच Define करते हैं।
चूंकि C# Program वास्तव में Type Declarations का एक समूह होता है, इसलिए जब हम C# Programming सीखते हैं, तो वास्तव में हमें विभिन्न प्रकार के C# Types को ही Create व Use करना सीखना होता है। इसलिए सबसे पहले हम यही समझने की कोशिश करते हैं कि C# Types वास्तव में क्या होते हैं।
Predefined Types
Types वास्तव में एक प्रकार का Template होते हैं, जिनका प्रयोग किसी Specific Type के Data Structure को Create करने के लिए किया जाता है। ये Template स्वयं Data Structure नहीं होता, बल्कि ये Template केवल इतना ही Specify करता है कि Create होने वाले Object की Characteristics क्या होंगी। यानी एक Type के Member कौन-कौन से होंगे और Type किस प्रकार की जरूरत को पूरा करने के लिए कौन-कौन से Operations Perform करेगा।
Type वास्तव में हमेंशा किसी न किसी Real World Object का Logical Description ही होते हैं और किसी Real World Object को Computer में हमेंशा Types के माध्यम से ही Logically Represent किया जाता है।
C# में हम जब भी कोई Type Define करना चाहते हैं, तो हमें mls Define करने के लिए निम्न Elements को Specify करना होता है:
- Name of the Type
- Data Structure for Data Members
- Behaviors and Constraints
जब एक बार हम किसी नए Type का Template Create कर लेते हैं, तो फिर हम हमारे Program में उस Type के आधार पर जितने चाहें उतने Objects Create कर सकते हैं। किसी Type के Template के आधार पर Create किए जाने वाले Object को उस Template Type का Instance कहा जाता है।
यानी Object व Instance दोनों एक ही Implementation के दो नाम हैं और C# Program में हम जितने भी Type के Object या Primary Data Type Declarations करते हैं, उन सभी को .NET Framework की BCL में विभिन्न Namespaces में Define किया गया है।
C# Program में हम जितने भी Types Create करते हैं, उन सभी में Data Members व Methods होते हैं। Data Members को Fields भी कहा जाता है, जो कि किसी Real World Object की Characteristics को Represent करता है। जबकि Method इन Characteristics को विभिन्न तरीकों से Access व Manipulate करने के लिए, इन पर विभिन्न प्रकार के Operations Perform करते हैं और इनकी State में परिवर्तन करते हैं अथवा इनके मानों को Access करते हुए इनके मानों को Return करते हैं।
C# में मूल रूप से दो प्रकार के Types होते हैं। पहले प्रकार के Types को Predefined Types कहा जाता है, जो कि .NET Framework में विभिन्न Namespaces में पहले से Exist हैं। जबकि दूसरे प्रकार के Types को User Defined Types कहा जाता है, जो कि हम एक Programmer की तरह स्वयं अपने Application की किसी जरूरत को पूरा करने के लिए किसी Real World Object को C# Program में Logically Represent करने हेतु Create करते हैं।
C# में जिन Types को पहले से Define किया जा चुका है, वे सभी Lowercase Characters द्वारा Represent होते हैं, जो कि सामान्यत: किसी .NET Framework Type के Shorthand Notations होते हैं। सामान्यत: इन Predefined Types को Primary Data Types भी कहते हैं।
C# में कुल 11 Numerical Primary Types को Define किया गया है, जिनकी Signed व Unsigned Range अलग-अलग होती है और इनके बारे में हम इस पुस्तक के “Data and Data Types” Section में विस्तार से Discuss कर चुके हैं। इनके अलावा C# में string, object व dynamic नाम के तीन और Non-Simple Types को भी .NET Framework में Define किया गया है।
Predefined Primary Types हमेंशा Data के किसी Single Item को Represent करते हैं, जिन्हें .NET Framework के अन्तर्गत विभिन्न Primary Types या Classes के रूप में Directly Map किया गया है, जिन्हें Use करने के लिए हम int, long, float आदि Keywords या Shorthand Notations का प्रयोग करते है।
यानी हम Primary Data Types की तरह जिन भी int, long, float, double आदि Keywords को Use करते हैं, उन्हें वास्तव में C# Compiler में Primary Data Type की तरह Define नहीं किया गया है। बल्कि सभी Primary Data Types वास्तव में .NET Framework के किसी Type के रूप में Exist है और इन Types के Shorthand Notation या Alias की तरह ही Use करने के लिए हम int, long, float, double आदि Keywords को उपयोग में लेते हैं।
इसलिए जब हम इन Keywords या Shorthand Notations को Use करते हुए कोई Variable या Constant Declare करते हैं, तो हम वास्तव में इन Keywords से Associated .NET Framework के किसी Type का Object या Instance ही Create कर रहे होते हैं। जिसका मतलब यही है कि C# में कोई भी Primary Data Type नहीं होता बल्कि सबकुछ किसी ना किसी Type का Object या Instance होता है।
इन सभी Primary Data Types Related .NET Framework Types के बारे में भी हम पुस्तक के पिछले Sections में विस्तार से Discuss कर चुके हैं। फिर भी Shorthand Notations Related Keywords व उनसे Associated .NET Framework Types को हम निम्न सारणी द्वारा सरल तरीके से Represent कर सकते हैं:
Name | Meaning | Range | .NET Framework Type | Default Value |
sbyte | 8-bit signed integer | -128 to 127 | System.SByte | 0 |
byte | 8-bit unsigned integer | 0 to 255 | System.Byte | 0 |
short | 16-bit signed integer | -32,768 to 32,767 | System.Int16 | 0 |
ushort | 16-bit unsigned integer | 0 to 65,535 | System.UInt16 | 0 |
int | 32-bit signed integer | -2,147,483,648 to 2,147,483,647 | System.Int32 | 0 |
uint | 32-bit unsigned integer | 0–4,294,967,295 | System.UInt32 | 0 |
long | 64-bit signed integer | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
System.Int64 | 0 |
ulong | 64-bit unsigned integer | 0 to 18,446,744,073,709,551,615 | System.UInt64 | 0 |
float | Single-precision float | 1.5×10-45 to 3.4×1038 | System.Single | 0.0f |
double | Double-precision float | 5×10-324 to 1.7×10308 | System.Double | 0.0d |
bool | Boolean | true, false | System.Boolean | false |
char | Unicode character | U+0000 to U+ffff | System.Char | \x0000 |
decimal | Decimal value with 28-significant-digit precision | ±1.0×1028 to ±7.9×1028 | System.Decimal | 0m |
C# Programs Create करते समय हमेंशा इन Shorthand Notations को ही उपयोग में लेना चाहिए न कि .NET Framework की उन मूल Types को, जिनके Shorthand Notations के रूप में Keywords Define किए गए है।
Name | Meaning | .NET Framework Type |
object | The base class from which all other types, including the simple types are derived | System.Object |
string | A sequence of zero or more Unicode characters | System.String |
dynamic | A type designed to be used with assemblies written in dynamic languages | No corresponding .NET type |
User Defined Types
C# के 16 Predefined Types के अलावा हम हमारी जरूरत के अनुसार किसी Real World Object को C# Program में Represent करने के लिए स्वयं के User Defined Data Types भी Create कर सकते हैं। C# हमें निम्नानुसार कुल 6 प्रकार के User Defined Data Types Create करने की सुविधा देता है:
- class Type
- struct Type
- array Type
- enum Type
- delegate Type
- interface Type
जब हम हमारे Application की Requirement के अनुसार किसी Real World Object को C# Program में Logically Represent करने के लिए अपना स्वयं का कोई User Defined Type Create करना चाहते हैं, तब हमें C# के Type Declaration Syntax का प्रयोग करना होता है, जिसमें हमें %
- नए Type का नाम Specify करना होता है।
- नए Type का प्रकार Specify करना होता है।
- नए Type के सभी Data Members व Methods को Specify करना होता है, जहां Data Members के रूप में हम Array व Delegate Type को छोडकर अपनी जरूरत के अनुसार किसी भी अन्य Type को Use कर सकते हैं।
एक बार जब हम हमारे नए Type का Definition Create कर लेते हैं, तो ये Definition एक प्रकार के Template की तरह होता है, जिसका प्रयोग Create किए गए नए Type का Object या Instance Create करने के लिए किया जा सकता है और इस Newly Created Type को Exactly उसी प्रकार से Use किया जा सकता है, जिस तरह से हम Predefined Types को Use किया जाता है।
Predefined Types को Use करते समय हमें केवल किसी Specific Type का Object Declare करना होता है। लेकिन जब हम स्वयं की जरूरत के अनुसार किसी Real World Object को C# Program में Logically Represent करना चाहते हैं, तो सबसे पहले हमें उस Real World Object को C# Syntaxes के अनुसार एक नए Type की तरह Define करना होता है।
ये Definition ही हमारे नए Type का Logical Description, Template, Model या Blueprint होता है और नए Type का Template Create होने के बाद उस नए Template के आधार पर Newly Created Type का Object या Instance Create या Declare करना पडता है।
इस तरह से User Defined Type को Use करने में दो Steps Involve होते हैं, जबकि Predefined Types को Use करने में केवल एक ही Step को Follow करना पडता है। यानी किसी का Object/Instance Declare/Create करना पडता है।
Stack and Heap – Different Memory Areas for Types
जब कोई C# Program Run हो रहा होता है, तो उसके Data Memory में Store होने जरूरी होते हैं, तभी वह Program Normal तरीके से Run हो सकता है। यानी किसी Program के Run होने के लिए सबसे पहले उसे Memory में Store या Load होना पडता है।
लेकिन जब कोई Program Memory में Load होता है, तो वह Program Memory के किस Area में Load होगा और Load होने के लिए Memory में कितनी Space Reserve करेगा, ये बात पूरी तरह से उसमें Use किए गए Types पर निर्भर करती है।
हमने पिछले Sections में जाना है कि C# में मूल रूप से दो तरह के Types होते हैं, जिन्हें Value Type व Reference Type के नाम से जाना जाता है। Value Types की Size हमेंशा निश्चित होती है, इसलिए Value Types हमेंशा Memory के Stack Area में Space Reserve करते हैं। जबकि Reference Types की Range कभी भी निश्चित नहीं होने की वजह से सभी Reference Types हमेंशा Memory के Heap Area में Space Reserve करते हैं।
Stack, Memory का एक ऐसा हिस्सा होता है, जो Last-In First-Out (LIFO) Data Structure की तरह काम करता है और हमारे C# Program के निम्नानुसार विभिन्न Value Types के Data को Store करता है:
- Program के विभिन्न Local Variables की Values को
- Program के Current Execution Environment को, यानी इस बात की जानकारी को कि Current Program कहां तक Execute हो चुका है और कौनसा अगला Statement Execute होना है। तथा
- Methods में Pass किए जाने वाले Parameters को।
इन सभी को Control व Handle करने का काम हमारे Computer का Operating System करता है। इसलिए हमें इनके बारे में कुछ भी करने की जरूरत नहीं होती है। फिर भी ये जानने के लिए कि हमारा Program Internally कैसे Flow हो रहा है और Program में Generate होने वाली Errors व Bugs को किस तरह से Handle किया जाना चाहिए, Stacks की Working को समझना हमारे लिए उपयोगी रहता है।
जब हम किसी C# Program को Run करते हैं, तो हमारे Computer के Memory के Stack Area की सामान्यत: निम्न Characteristics होती हैं:
- Stack में हमेंशा Top पर नया Data Item Insert होता है और Top से ही Data Item Remove होता है।
- Stack में नया Data Insert करने की प्रक्रिया को Push करना कहा जाता है। जबकि
- Stack के Top से किसी Data Item को Remove करने की प्रक्रिया को Pop करना कहा जाता है।
Heap Area Memory का वह हिस्सा होता है, जहां हमारे Computer के Operating System द्वारा किसी Specific Type के Data Object को Memory Allocate किया जाता है। Heap की विशेषता ये होती है कि इसमें कोई भी Object किसी भी Memory Location पर Insert या किसी भी Memory Location से Remove हो सकता है। यानी Stack की तरह सभी Data Top से ही Insert या Remove नहीं होते।
हालांकि हमारा Program Heap Area में Program के Data को Store तो कर सकता है, लेकिन Explicitly Delete नहीं कर सकता। बल्कि Delete होने वाले सारे Objects की Memory Release करने का काम .NET Platform का Garbage Collector (GC) उस समय Automatically करता है, जब किसी Object को हमारे Program का कोई भी हिस्सा Reference या Access नहीं कर रहा होता है।
Value Types and Reference Types
Value Types व Reference Types दोनों ही Memory में Store होते हैं, लेकिन दोनों के ही Store होने के तरीके में अन्तर होता है। Value Types हमेंशा Single Memory Segment यानी Stack में Store होते हैं, जिनमें Actual Data होता है। जबकि Reference Types हमेंशा Double Memory Segment में Store होते हैं, जहां-
- पहले Segment में Actual Data होता है और ये Segment हमेंशा Memory के Heap Area में Reserve होता है। जबकि
- दूसरे Segment में हमेंशा उस पहले Segment का Reference होता है, जो Heap Area में Stored Actual Data को Point करता है। ये Pointer हमेंशा Stack में Store रहता है। यानी Reference Type का Actual Data, Heap Area में Store होता है और उस Actual Data का एक Reference या Pointer Stack में Store होता है।
इस प्रक्रिया को हम निम्न चित्र द्वारा ज्यादा आसानी से समझ सकते हैं:
चूंकि C# में Primary Data Type जैसा कुछ नहीं होता, बल्कि जो होता है, वह सबकुछ Type होता है। इसलिए जब हम किसी Type में Data Member के रूप में किसी दूसरे Type का Object Create करते हैं, तो हम वास्तव में एक Type Definition की Body में दूसरे Type को Declare कर रहे होते हैं और इस प्रकार के Reference Types Memory में सामान्य Reference Type की तरह नहीं बल्कि कुछ अलग तरीके से Store होते हैं।
ऐसे Object का Data Part तो हमेंशा Heap में ही Store होता है, जैसाकि पिछले चित्र में दर्शाया गया है। लेकिन Value के रूप में जब स्वयं एक Reference Type होता है, तब उस Reference Type का Reference, Stack या Heap दोनों में Store हो सकता है। जैसे:
जैसाकि हम इस चित्र द्वारा समझ सकते हैं कि MyType Object Heap Area में Store हो रहा है, जिसमें Data Part की तरह स्वयं एक और Reference Type का Reference Stored है और वह Reference स्वयं Heap Area में Stored एक और Object का Reference Hold किए हुए है।
इस तरह से हम समझ सकते हैं कि .NET Platform में Reference Type हमेंशा Heap Area में ही Store होता है, भले ही उसे किसी अन्य Type के Data Member की तरह ही क्यों न Specify किया गया हो। जबकि यदि Nested Type में कोई Value Type Member हो, तो वह Member भी किसी अन्य Reference Type में Nested होने की वजह से Heap Area में ही Stored रहता है।
C# Programming Language द्वारा Supported विभिन्न Value Type व Reference Types को हम निम्नानुसार सारणी द्वारा आसानी से समझ सकते हैं:
ये Article इस वेबसाईट पर Selling हेतु उपलब्ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी।
C#.NET in Hindi | Page:908 | Format: PDF