What is a Namespace in C#

What is a Namespace in C#: Namespace हमारे Codes को Logically Group करने का एक तरीका मात्र है, जिससे एक से ज्यादा Namespaces में यदि समान नाम के Types हों, तो वे एक दूसरे के साथ किसी भी प्रकार का Conflict न करें।

यानी Name Clash से बचने का सबसे बेहतर तरीका यही है कि हम हमारे Reusable Codes को किसी Namespace Block के बीच Specify करें और हमने इस पुस्तक में अभी तक जितने भी Programs Create किए हैं, उन सभी Programs को एक Unique namespace Block के बीच ही Enclose किया है। ताकि यदि हमें उन Files में Specify की गई किसी Class की जरूरत हो, तो केवल उन Classes को Namespace के साथ Dot Operator का प्रयोग करते हुए Reference करके प्राप्त कर सकें।

उदाहरण के लिए हमने हमारे पिछले Program में MyLibrary Namespace में Specified दो Types को UsingMyLibrary.cs File में Use किया है। लेकिन हम इन Types को उसी स्थिति में Use कर पा, हैं, जबकि हमने Source File की शुरूआत में ही using Statement का प्रयोग करके MyLibrary को अपने Current Program में Add किया है।

जबकि यदि हम using Statement का प्रयोग करके इन्हें अपने Program में Include नहीं करते, तो हमें MyNewClassType MyNewStructureType को Use करने के लिए निम्नानुसार Fully Qualified नामों को Use करना पडता-

    class UsingMyLibrary
    {
        public static void Main()
        {
            MyLibrary.MyNewClassType obj = new MyLibrary.MyNewClassType();
            obj.Display();

            MyLibrary.MyNewStructureType variable = new MyLibrary.MyNewStructureType();
            variable.Display();
        }

Namespaces का प्रयोग समान प्रकार के या समान विषय से सम्बंधित Types को Group करने के लिए किया जाता है, ताकि समान प्रकार की या समान विषय से सम्बंधित जरूरतों को पूरा करने से सम्बंधित सभी .NET Types को एक Group के रूप में Define किया जा सके और इस Group को एक नाम Specify किया जा सके। ये नाम ही Namespace होता है, जिसमें Defined Types को Use करने के लिए हमें या तो using Statement को Use करना होता है या फिर Fully Qualified नाम को Use करना होता है।

Namespace Name के रूप में हम किसी भी Valid Identifier Name को Use कर सकते हैं और C# के किसी भी Identifier की तरह ही Namespace Identifier भी Case Sensitive होता है और सभी अन्‍य Identifier Naming Rules को Follow करता है।

Namespaces are Partial

हमने Partial Classes के बारे में प<ा था तब यही समझा था कि हम एक ही नाम की Class को एक से ज्यादा Source Files में Define कर सकते हैं। ठीक उसी तरह से हम एक ही Namespace में जिन भी Types को Add करना चाहते हैं, उन्हें एक ही Source File में Define करना जरूरी नहीं है।

बल्कि हम अलग-अलग Source Files में समान नाम का Namespace Specify करके उसमें जो भी Types Define करेंगे, वे सभी Types उसी Namespace में Add होंगे, फिर भले ही समान Namespace को कई Source Files में Define क्यों न किया गया हो। जैसे:

File Name: MyLibraryPart1.cs
using System;

namespace MyLibrary
{
    public class MyNewClassType
    {
        public void Display()
        {
            Console.WriteLine("Namespace: MyLibrary \tClass: MyNewClassType");
        }
    }
}
File Name: MyLibraryPart2.cs
using System;

namespace MyLibrary
{
    public struct MyNewStructureType
    {
        public void Display()
        {
            Console.WriteLine("Namespace: MyLibrary \tClass: MyNewStructureType");
        }
    }
}

यहां हमने हमारे MyLibrary नाम के Namespace में Defined दोनों Types को दो अलग Files में Define कर दिया है लेकिन दोनों ही Files में हमने समान Namespace Block में ही दोनों Types को Define किया है। इसलिए हालांकि MyNewClassType MyNewStructureType दो अलग Source Files में Defined हैं, फिर भी ये दोनों समान Namespace में ही Exist हैं।

जब हम इस प्रकार से किसी Namespace को अलग-अलग Source Files के Across Define करते हैं, तो फिर इनको एक DLL Library के रूप में Convert करने के लिए हमें Command Prompt पर निम्नानुसार तरीके से सभी Source Files को Specify करना जरूरी हो जाता है:

csc /t:library /out:MyLibrary.dll MyLibraryPart1.cs MyLibraryPart2.cs

Source File Compilation के लिए इस Command Line को Use करने पर हमें जो DLL Library File प्राप्त होती है, उसका नाम MyLibrary.dll होता है, क्योंकि हमने /out:MyLibrary.dll Flag के साथ अपनी Output File का यही नाम Specify किया है। जबकि /t:library Flag का प्रयोग करके हमने C# Compiler को ये बताया है की Compilation द्वारा Generate होने वाली Assembly File एक DLL Library File है।

जब हम इस Command Line Compilation को Use करते हैं, तब भी MyLibrary.dll नाम की File ही Generate होती है। इसलिए ये जानने के लिए कि हमारी MyLibrary.dll File में MyNewClassType MyNewStructureType दोनों Types Exist हैं या नहीं, हम हमारे UsingMyLibrary.cs File को ही निम्नानुसार Command Line Parameters के माध्‍यम से फिर से Compile करके Run कर सकते हैं:

C:\…\> csc /r:MyLibrary.dll UsingMyLibrary.cs

यदि इस बार भी इस Command Line Statement के माध्‍यम से UsingMyLibrary.cs File को Compile करने पर वही Output प्राप्त होता है, जो पहले प्राप्त हुआ था, तो इसका मतलब यही है कि हमारी MyLibrary.dll File में MyNewClassType MyNewStructureType दोनों Types Exist हैं, जबकि हमने इन्हें दो अलग Files में Define किया था।

Namespace Nesting

BCL में बहुत सारे Namespaces को Define किया गया है, जैसे System, System.Data, System.Drawing, System.IO, Microsoft.CSharp, Microsoft.VisualBasic आदि। साथ ही C# में हम Namespace की Nesting भी कर सकते हैं।

इसीलिए जब हम Namespace की Nesting करते हैं, तो विभिन्न Namespaces को भी using Statement के साथ Specify करने के बाद ही हम उनमें Defined Types को Use कर सकते हैं अथवा हमें सभी Namespaces को Fully Qualified Name बनाने के लिए Dot Operators को Use करना होता है। जैसे:

System.Windows.Forms
System.Windows.Controls
System.Data.OleDb
System.Data.SqlClient

इसी तरह से यदि हम चाहें तो हम हमारे Codes की भी Nested Namespaces में Nesting कर सकते हैं। जैसे:

	namespace BccFalna
	{
		namespace Coaching
		{
			public class Classes
			{
				//Members
			}

			public struct Fees
			{
				//Members
			}
		}

		namespace Selling
		{
			public class EBooks
			{
				//Members
			}

			public struct Projects
			{
				//Members
			}
		}
	}

अब यदि Selling Namespace के Types को किसी दूसरी External Class File में Use करना चाहें, तो या तो हमें निम्नानुसार using Statement Use करना होगा:

using BccFalna.Selling;

या फिर हमें निम्नानुसार Fully Qualified Name Use करते हुए Selling Namespace के Types को Use करना होगा:

BccFalna.Selling.EBooks MyEBooks = new BccFalna.Selling.EBooks();

जिस तरह से हम एक ही Source File में एक से ज्यादा Classes Define कर सकते हैं, उसी तरह से हम एक ही Source File में एक से ज्यादा Namespaces भी Define कर सकते हैं और जब हम एक ही Source File में बहुत सारे Namespaces Define करके उन्हें एक DLL Library के रूप में Convert कर लेते हैं, तो उस Library का Reference अपने Project के साथ Add करने पर उस Library में उपलब्‍ध सभी Namespaces हमारे Project हेतु Access होने के लिए Available हो जाते हैं।

हालांकि हम समान Source File में एक ही Namespace के बीच अन्‍य Namespace की Nesting कर सकते हैं। लेकिन यदि हम चाहें, तो दो अलग Files में Defined Namespace में भी Nesting की जा सकती है। अथवा हम समान File में भी दो अलग-अलग Namespaces को इस तरह से Define कर सकते हैं, कि वे Indirectly Nested हो जाते हैं।

Normal Nesting के बारे में हम पिछले Code Fragment के माध्‍यम से आसानी से समझ सकते हैं। जबकि यदि हम चाहें, तो उपरोक्त Code Fragment को निम्नानुसार तरीके से Specify करके भी हम Nesting कर सकते हैं:

	namespace BccFalna
	{
		namespace Coaching
		{
			public class Classes
			{
				//Members
			}

			public struct Fees
			{
				//Members
			}
		}
	}

	// Possible to use following Namespace Nesting Pattern in Same File or Another File
	namespace BccFalna.Selling
	{
		public class EBooks
		{
			//Members
		}
		public struct Projects
		{
			//Members
		}
	}

इस Code में हमने BccFalna.Selling Namespace के लिए जो Declaration किया है, वह Declaration भी Nesting ही है। यानी इस Declaration द्वारा भी C# Compiler को यही Instruction मिलता है कि हम EBooks व Projects Types को BccFalna Namespace के अन्दर Selling नाम के Sub-Namespace यानी Nested Namespace में Specify कर रहे हैं।

यदि हम इस तरह से Nested Namespace Create करते हैं, तो जरूरी नहीं है कि हम सभी Nested Namespaces को एक ही Source File में Create करें। क्योंकि यहां Discussed दूसरे तरीके का प्रयोग करके भी हम किसी अलग Source File में Nested Namespace Create कर सकते हैं।

using Directive

इस Directive का प्रयोग करके हम किसी Namespace को अपने Current Program में Use करने की क्षमता प्राप्त करते हैं। यदि हम हमारे Current Program में किसी Namespace के सभी Types को Import करना चाहते हैं, तो जब using Directive को निम्नानुसार तरीके से Use करते हैं:

using System;

ये Statement हमारे Current Program के लिए System Namespace के सभी Types को Access करने के लिए Available कर देता है। लेकिन कई बार हमें किसी Namespace के बहुत कम Types को उपयोग में लेने की जरूरत होती है।

इस स्थिति में हमें पूरे Namespace को Current Program में Import करने की जरूरत नहीं होती। बल्कि हम चाहें तो Fully Qualified Name का प्रयोग करके किसी भी Namespace के किसी भी Type को Directly Access कर सकते हैं। जैसे:

System.Console.WriteLine();

जब हम इस तरह का Fully Qualified Name Statement Use करते हैं, तो हमें System Namespace को अपने Current Program में using Directive का प्रयोग करके Import करने की जरूरत नहीं होती।

कई बार स्थिति ऐसी होती है कि किसी Type को कई Level की Nesting में Define किया गया होता है। इसलिए जब हम ऐसे किसी Type को Fully Qualified Name द्वारा Use करना चाहते हैं, तो हमें बार-बार बहुत ज्यादा Typing करना पडता है। इस प्रकार की असुविधा से बचने के लिए C# हमें using Directive का प्रयोग करके किसी Namespace का Alias Create करने की भी सुविधा देता है। जैसे:

using Print = System.Console;

यदि हम इस using Directive को अपने किसी Program में Specify करते हैं, तो उस Program में जहां कहीं पर भी हमें System.Console की जरूरत हो वहां हम Alternative के रूप में Print शब्द को Use कर सकते हैं। जैसे:

System.Console.WriteLine(“Hello! This is the Message.”);

इसी Statement को हम निम्नानुसार भी लिख सकते हैं:

Print.WriteLine(“Hello! This is the Message.”);

यानी दोनों ही Statement में कोई अन्तर नहीं है और हम दोनों में से किसी को भी अपनी जरूरत के अनुसार उपयोग में ले सकते हैं।

Namespace Alias Qualifier

हालांकि Namespaces का प्रयोग करके हम Name Conflict की समस्या से बच सकते हैं लेकिन Namespaces का प्रयोग करने मात्र से Conflicting की समस्या पूरी तरह से समाप्त नहीं हो जाती। क्योंकि दो अलग Applications के लिए समान नाम के दो Namespace बना, जा सकते हैं। साथ ही दोनों Namespace में समान नाम के Types भी Define किए जा सकते हैं।

चूंकि C# के Namespace Additive होते हैं, यानी अलग-अलग Source Files में समान नाम के Namespace को Define किया जा सकता है और सभी Namespaces के लिए Defined सभी Types एक Single Namespace का ही हिस्सा होते हैं।

ऐसे में यदि दो अलग Libraries हों, जिनमें समान नाम के Namespace में कोई समान नाम का Type Defined हो, तो निश्चित रूप से Name Conflicting की समस्या पैदा हो सकती है।

इसलिए इस तरह से भी Name Conflicting की समस्या पैदा न हो, इसके लिए C# में Namespace Alias Qualifier (::) को Include किया गया है, जिसे C++ में Scope Resolution Operator के नाम से जाना जाता है और इस Operator का Namespace के साथ Explicitly Use करके हम इस तरह की Name Conflicting से बच सकते हैं। इसे निम्नानुसार Use किया जाता है:

NamespaceAlias :: identifier

जहां NamespaceAlias हमारे Namespace का वह Alias होता है, जिसे हम using Directive का प्रयोग करके Define करते हैं। जबकि identifier के रूप में हमें Namespace के Member के नाम को Specify करना होता है। जैसे:

File Name: NamespaceAliasQualifierOperator.cs
using System;
using NS1;
using NS2;

namespace NS1
{
    public class MyClass
    {
        public void Display()
        {
            Console.WriteLine("Display() Method of MyClass in NS1");
        }
    }
}

namespace NS2
{
    public class MyClass
    {
        public void Display()
        {
            Console.WriteLine("Display() Method of MyClass in NS2");
        }
    }
}

class UsingMyClass
{
    public static void Main()
    {
        MyClass myObject = new MyClass();
        myObject.Display();
    }
}

Output:
NamespaceAliasQualifierOperator.cs(31,4): error CS0104: 'MyClass' is an ambiguous reference between 'NS1.MyClass' and 'NS2.MyClass'
NamespaceAliasQualifierOperator.cs(7,16): (Location of symbol related to previous error)
NamespaceAliasQualifierOperator.cs(18,16): (Location of symbol related to previous error)
NamespaceAliasQualifierOperator.cs(31,27): error CS0104: 'MyClass' is an ambiguous reference between 'NS1.MyClass' and 'NS2.MyClass'
NamespaceAliasQualifierOperator.cs(7,16): (Location of symbol related to previous error)
NamespaceAliasQualifierOperator.cs(18,16): (Location of symbol related to previous error)

जब हम इस Program को Run करते हैं, तो हमें उपरोक्तानुसार Output के रूप में Compile Time Error प्राप्त होता है। क्योंकि इस Program में हमने NS1 NS2 नाम के दो Namespace Create किए हैं और दोनों ही Namespaces में MyClass नाम की एक समान Class है, जिसमें Display() नाम का समान Method है।

इसलिए जब हम हमारे इस Program में निम्नानुसार using Directive द्वारा इन दोनों Namespaces को Current Program में Import करते हैं:

using NS1;
using NS2;

तो दोनों ही Namespaces से समान नाम की Class Import होती है। परिणामस्वरूप जब हम Main() Method में निम्नानुसार MyClass Type का myObject नाम का एक Object Create करते हैं:

MyClass myObject = new MyClass();

तो C# Compiler Confuse हो जाता है कि हम किस Namespace के MyClass की बात कर रहे हैं, क्योंकि NS1 NS2 दोनों को Current Program में Import करने की वजह से दोनों ही Namespace की MyClass नाम की Class Current Program में Use होने के लिए Accessible है।

परिणामस्वरूप C# Compiler अपने इस Confusion को उपरोक्तानुसार एक Ambiguous Error के रूप में Return करता है। Namespace Alias Qualifier इसी समस्या का समाधान प्रस्तुत करता है, जिसे हम निम्न Program द्वारा आसानी से समझ सकते हैं:

File Name: UsingNamespaceAliasQualifierOperator.cs
using System;
using NS1;
using NS2;

using MyNS = NS1;
using YourNS = NS2;

namespace NS1
{
    public class MyClass
    {
        public void Display()
        {
            Console.WriteLine("Display() Method of MyClass in NS1");
        }
    }
}

namespace NS2
{
    public class MyClass
    {
        public void Display()
        {
            Console.WriteLine("Display() Method of MyClass in NS2");
        }
    }
}

class UsingMyClass
{
    public static void Main()
    {
        MyNS::MyClass myObject = new MyNS::MyClass();
        myObject.Display();

        YourNS::MyClass yourObject = new YourNS::MyClass();
        yourObject.Display();
    }
}

Output:
   Display() Method of MyClass in NS1
   Display() Method of MyClass in NS2

जैसाकि हम इस Program के Output द्वारा समझ सकते हैं कि ये Program अब Normal तरीके से काम कर रहा है, क्योंकि इस Program में हमने निम्नानुसार तरीके से NS1 व NS2 की Aliasing कर दी है:

using MyNS = NS1;
using YourNS = NS2;

जिसकी वजह से अब हम NS1 को MyNS NS2 को YourNS नाम से Refer कर सकते हैं। फिर हमने Main() Method में दोनों MyClass Type को अलग Represent करने के लिए निम्नानुसार तरीके से Namespace Alias Qualifier का प्रयोग किया है:

MyNS::MyClass myObject = new MyNS::MyClass();
. . .
YourNS::MyClass yourObject = new YourNS::MyClass();
. . .

जिसकी वजह से C# Compiler को इस बार बिना किसी तरह के Confusion के इस बात का पता रहता है कि उसे कब और किस Statement के Response में किस Namespace की MyClass Type को Access करना है।

Global Namespaces

जब हम हमारे किसी Program को Create करते समय किसी Namespace को Declare नहीं करते, तब भी हमारा Code एक Namespace में ही Create होता है, जिसे Global Namespace के नाम से जाना जाता है। इसीलिए हमें हमारे हर Program को किसी Namespace में Define करना जरूरी नहीं होता।

लेकिन Namespaces वास्तव में हमें हमारे Code को और ज्यादा बेहतर तरीके से Organize करने की सुविधा Provide करते हैं। इसलिए जब हम हमारा हर Code किसी Specific Namespace में Define करते हैं, तो हमारे Code द्वारा किसी अन्‍य Code के साथ Name Conflict की समस्या कभी भी पैदा नहीं होती। इसलिए अपने हर Code को किसी Specific Unique Namespace में Enclose करना हमेंशा अच्छा ही रहता है।

चूंकि हम हमारे Code को जब किसी भी तरह का Namespace Specify किए बिना लिखते हैं, तो हमारा Code हमेंशा एक Global Namespace में होता है। इसलिए ऐसी भी स्थिति पैदा हो सकती है, जहां किसी Global Namespace व Imported Namespace में समान नाम की Class हो, जिसे समान प्रोग्राम में Use करना हो।

इस प्रकार की स्थिति होने पर Global Namespace को हमेंशा global शब्द से Refer किया जाता है। जैसे:

File Name: GlobalNamespaceWithAliasQualifierOperator.cs
using System;
using NS1;

using MyNS = NS1;

namespace NS1
{
    public class MyClass
    {
        public void Display()
        {
            Console.WriteLine("Display() Method of MyClass in NS1");
        }
    }
}

public class MyClass
{
    public void Display()
    {
        Console.WriteLine("Display() Method of MyClass in Global Namespace");
    }
}

class UsingMyClass
{
    public static void Main()
    {
        MyNS::MyClass myObject = new MyNS::MyClass();
        myObject.Display();

        global::MyClass yourObject = new global::MyClass();
        yourObject.Display();
    }
}

// Output:
   Display() Method of MyClass in NS1
   Display() Method of MyClass in Global Namespace

इस Program में हमने NS1 नाम का एक Namespace Create किया है, जिसमें MyClass नाम की Class है। साथ ही Current Source File में भी हमने MyClass नाम की एक Class Create की है।

इसलिए Current Program में फिर से Name Conflicting की समस्या पैदा हो जाती है। इस समस्या से बचने के लिए ही हमने हमारे Global Namespace को Represent करने के लिए निम्नानुसार तरीके से Declaration किया है:

global::MyClass yourObject = new global::MyClass();

क्योंकि यदि हम इस तरह से global Namespace को Specify करते हुए Namespace Alias Qualifier का प्रयोग न करें, तो हमारा Program पिछले Example की तरह ही Name Conflicting यानी Ambiguous Error Return करेगा।

What is Assembly in C#
Assembly in .NET - Everything

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS