C# Language
विरासत
खोज…
वाक्य - विन्यास
- वर्ग DerivedClass: BaseClass
- वर्ग DerivedClass: BaseClass, IExampleInterface
- वर्ग DerivedClass: BaseClass, IExampleInterface, IAnotherInterface
टिप्पणियों
कक्षाएं केवल एक ही वर्ग से सीधे विरासत में मिल सकती हैं, लेकिन (इसके बजाय या एक ही समय में) एक या अधिक इंटरफेस को लागू कर सकती हैं।
संरचनाएं इंटरफेस को लागू कर सकती हैं लेकिन किसी भी प्रकार से स्पष्ट रूप से विरासत में नहीं मिल सकती हैं। वे स्पष्ट रूप से System.ValueType
से विरासत में प्राप्त करते हैं, जो बदले में सीधे System.Object
से विरासत में System.Object
।
स्टेटिक क्लास इंटरफेस को लागू नहीं कर सकते हैं ।
बेस क्लास से इनहेरिट करना
डुप्लिकेट कोड से बचने के लिए, एक सामान्य वर्ग में आधार के रूप में सामान्य तरीकों और विशेषताओं को परिभाषित करें:
public class Animal
{
public string Name { get; set; }
// Methods and attributes common to all animals
public void Eat(Object dinner)
{
// ...
}
public void Stare()
{
// ...
}
public void Roll()
{
// ...
}
}
अब जब आपके पास एक वर्ग है जो सामान्य रूप से Animal
का प्रतिनिधित्व करता है, तो आप एक वर्ग को परिभाषित कर सकते हैं जो विशिष्ट जानवरों की ख़ासियत का वर्णन करता है:
public class Cat : Animal
{
public Cat()
{
Name = "Cat";
}
// Methods for scratching furniture and ignoring owner
public void Scratch(Object furniture)
{
// ...
}
}
कैट क्लास को न केवल इसकी परिभाषा में वर्णित विधियों को स्पष्ट रूप से प्राप्त करने की अनुमति मिलती है, बल्कि सामान्य Animal
आधार वर्ग में परिभाषित सभी विधियां भी। कोई भी जानवर (चाहे वह बिल्ली था या नहीं) खा सकता है, घूर सकता है, या लुढ़क सकता है। एक जानवर, जब तक यह एक बिल्ली भी नहीं था, खरोंच नहीं कर पाएगा। फिर आप अन्य जानवरों का वर्णन करने वाली अन्य कक्षाओं को परिभाषित कर सकते हैं। (इस तरह के गोफर के रूप में फूलों के बागानों को नष्ट करने के लिए एक विधि और आलसी बिना किसी अतिरिक्त तरीकों के साथ।)
एक वर्ग से इनहेरिट करना और एक इंटरफ़ेस लागू करना
public class Animal
{
public string Name { get; set; }
}
public interface INoiseMaker
{
string MakeNoise();
}
//Note that in C#, the base class name must come before the interface names
public class Cat : Animal, INoiseMaker
{
public Cat()
{
Name = "Cat";
}
public string MakeNoise()
{
return "Nyan";
}
}
एक वर्ग से प्रवेश करना और कई इंटरफेस को लागू करना
public class LivingBeing
{
string Name { get; set; }
}
public interface IAnimal
{
bool HasHair { get; set; }
}
public interface INoiseMaker
{
string MakeNoise();
}
//Note that in C#, the base class name must come before the interface names
public class Cat : LivingBeing, IAnimal, INoiseMaker
{
public Cat()
{
Name = "Cat";
HasHair = true;
}
public bool HasHair { get; set; }
public string Name { get; set; }
public string MakeNoise()
{
return "Nyan";
}
}
परीक्षण और विरासत को नेविगेट करना
interface BaseInterface {}
class BaseClass : BaseInterface {}
interface DerivedInterface {}
class DerivedClass : BaseClass, DerivedInterface {}
var baseInterfaceType = typeof(BaseInterface);
var derivedInterfaceType = typeof(DerivedInterface);
var baseType = typeof(BaseClass);
var derivedType = typeof(DerivedClass);
var baseInstance = new BaseClass();
var derivedInstance = new DerivedClass();
Console.WriteLine(derivedInstance is DerivedClass); //True
Console.WriteLine(derivedInstance is DerivedInterface); //True
Console.WriteLine(derivedInstance is BaseClass); //True
Console.WriteLine(derivedInstance is BaseInterface); //True
Console.WriteLine(derivedInstance is object); //True
Console.WriteLine(derivedType.BaseType.Name); //BaseClass
Console.WriteLine(baseType.BaseType.Name); //Object
Console.WriteLine(typeof(object).BaseType); //null
Console.WriteLine(baseType.IsInstanceOfType(derivedInstance)); //True
Console.WriteLine(derivedType.IsInstanceOfType(baseInstance)); //False
Console.WriteLine(
string.Join(",",
derivedType.GetInterfaces().Select(t => t.Name).ToArray()));
//BaseInterface,DerivedInterface
Console.WriteLine(baseInterfaceType.IsAssignableFrom(derivedType)); //True
Console.WriteLine(derivedInterfaceType.IsAssignableFrom(derivedType)); //True
Console.WriteLine(derivedInterfaceType.IsAssignableFrom(baseType)); //False
एक सार आधार वर्ग का विस्तार
इंटरफेस के विपरीत, जिसे कार्यान्वयन के लिए अनुबंध के रूप में वर्णित किया जा सकता है, अमूर्त वर्ग विस्तार के अनुबंध के रूप में कार्य करते हैं।
एक सार वर्ग को तत्काल नहीं किया जा सकता है, इसे विस्तारित किया जाना चाहिए और परिणामी वर्ग (या व्युत्पन्न वर्ग) को फिर से त्वरित किया जा सकता है।
जेनेरिक कार्यान्वयन प्रदान करने के लिए सार वर्गों का उपयोग किया जाता है
public abstract class Car
{
public void HonkHorn() {
// Implementation of horn being honked
}
}
public class Mustang : Car
{
// Simply by extending the abstract class Car, the Mustang can HonkHorn()
// If Car were an interface, the HonkHorn method would need to be included
// in every class that implemented it.
}
उपरोक्त उदाहरण से पता चलता है कि कार का विस्तार करने वाला कोई भी वर्ग स्वचालित रूप से कार्यान्वयन के साथ ऑनकहॉर्न विधि प्राप्त करेगा। इसका मतलब यह है कि नई कार बनाने वाले किसी भी डेवलपर को इस बारे में चिंता करने की जरूरत नहीं होगी कि यह हॉर्न कैसे देगा।
एक उपवर्ग में निर्माता
जब आप एक आधार वर्ग का एक उपवर्ग बनाने के लिए, आप का उपयोग करके आधार वर्ग का निर्माण कर सकते : base
उपवर्ग निर्माता के मापदंडों के बाद।
class Instrument
{
string type;
bool clean;
public Instrument (string type, bool clean)
{
this.type = type;
this.clean = clean;
}
}
class Trumpet : Instrument
{
bool oiled;
public Trumpet(string type, bool clean, bool oiled) : base(type, clean)
{
this.oiled = oiled;
}
}
विरासत। कंस्ट्रक्टर्स का कॉल सीक्वेंस
गौर कीजिए कि हमारे पास एक क्लास Animal
जिसमें एक चाइल्ड क्लास Dog
class Animal
{
public Animal()
{
Console.WriteLine("In Animal's constructor");
}
}
class Dog : Animal
{
public Dog()
{
Console.WriteLine("In Dog's constructor");
}
}
डिफ़ॉल्ट रूप से प्रत्येक वर्ग अंतर्निहित रूप से Object
क्लास को विरासत में लेता है।
यह उपरोक्त कोड के समान है।
class Animal : Object
{
public Animal()
{
Console.WriteLine("In Animal's constructor");
}
}
Dog
क्लास का एक उदाहरण बनाते समय, बेस क्लास के डिफॉल्ट कंस्ट्रक्टर (बिना मापदंडों के) को कॉल किया जाएगा, अगर पैरेंट क्लास में किसी अन्य कंस्ट्रक्टर को कोई स्पष्ट कॉल नहीं आती है । हमारे मामले में, पहले Object's
निर्माता कहा जाएगा, फिर Animal's
और अंत में Dog's
कंस्ट्रक्टर।
public class Program
{
public static void Main()
{
Dog dog = new Dog();
}
}
आउटपुट होगा
पशु के निर्माण में
डॉग के निर्माता में
स्पष्ट रूप से माता-पिता के निर्माता को बुलाओ।
उपरोक्त उदाहरणों में, हमारा Dog
क्लास कंस्ट्रक्टर Animal
क्लास के डिफॉल्ट कंस्ट्रक्टर को कॉल करता है। यदि आप चाहें, तो आप निर्दिष्ट कर सकते हैं कि किस निर्माता को बुलाया जाना चाहिए: किसी भी निर्माता को कॉल करना संभव है जो मूल वर्ग में परिभाषित किया गया है।
गौर कीजिए कि हमारे पास ये दो वर्ग हैं।
class Animal
{
protected string name;
public Animal()
{
Console.WriteLine("Animal's default constructor");
}
public Animal(string name)
{
this.name = name;
Console.WriteLine("Animal's constructor with 1 parameter");
Console.WriteLine(this.name);
}
}
class Dog : Animal
{
public Dog() : base()
{
Console.WriteLine("Dog's default constructor");
}
public Dog(string name) : base(name)
{
Console.WriteLine("Dog's constructor with 1 parameter");
Console.WriteLine(this.name);
}
}
यहाँ क्या हो रहा है?
हमारे पास प्रत्येक कक्षा में 2 निर्माता हैं।
base
क्या अर्थ है?
base
मूल वर्ग का एक संदर्भ है। हमारे मामले में, जब हम इस तरह से Dog
क्लास का एक उदाहरण बनाते हैं
Dog dog = new Dog();
रनटाइम पहले Dog()
कॉल करता है, जो कि पैरामीटर रहित कंस्ट्रक्टर है। लेकिन इसका शरीर तुरंत काम नहीं करता है। कंस्ट्रक्टर के कोष्ठकों के बाद हमारे पास एक ऐसी कॉल है: base()
, जिसका अर्थ है कि जब हम डिफॉल्ट Dog
कंस्ट्रक्टर को कॉल करते हैं, तो यह बदले में माता-पिता के डिफॉल्ट कंस्ट्रक्टर को कॉल करेगा। माता-पिता के कंस्ट्रक्टर के चलने के बाद, यह वापस आ जाएगा और फिर, अंत में Dog()
कंस्ट्रक्टर बॉडी को चलाएगा।
तो आउटपुट इस तरह होगा:
पशु का डिफ़ॉल्ट निर्माता
कुत्ते का डिफ़ॉल्ट निर्माता
अब क्या होगा अगर हम एक पैरामीटर के साथ Dog's
निर्माता को बुलाते हैं?
Dog dog = new Dog("Rex");
आप जानते हैं कि माता-पिता वर्ग के सदस्य जो निजी नहीं हैं, उन्हें बाल वर्ग द्वारा विरासत में मिला है, जिसका अर्थ है कि Dog
का भी name
क्षेत्र होगा।
इस मामले में हमने अपने कंस्ट्रक्टर को एक तर्क दिया। यह अपनी बारी में एक पैरामीटर के साथ पैरेंट क्लास के कंस्ट्रक्टर को तर्क देता है, जो name
फ़ील्ड को इनिशियलाइज़ करता है।
आउटपुट होगा
Animal's constructor with 1 parameter
Rex
Dog's constructor with 1 parameter
Rex
सारांश:
प्रत्येक वस्तु का निर्माण आधार वर्ग से शुरू होता है। विरासत में, जो वर्ग पदानुक्रम में हैं, जंजीर हैं। जैसा कि सभी वर्ग Object
से प्राप्त होते हैं, किसी भी ऑब्जेक्ट को बनाते समय कहा जाने वाला पहला कंस्ट्रक्टर Object
क्लास कंस्ट्रक्टर होता है; फिर श्रृंखला में अगले निर्माता को बुलाया जाता है और केवल उन सभी को बुलाया जाता है, जिसके बाद वस्तु बनाई जाती है
आधार कीवर्ड
- बेस कीवर्ड का उपयोग बेस क्लास के सदस्यों को एक व्युत्पन्न वर्ग के भीतर से एक्सेस करने के लिए किया जाता है:
- बेस क्लास पर एक विधि को कॉल करें जिसे किसी अन्य विधि द्वारा ओवरराइड किया गया है। यह निर्दिष्ट करें कि व्युत्पन्न वर्ग के उदाहरण बनाते समय किस बेस-क्लास कंस्ट्रक्टर को बुलाया जाना चाहिए।
इनहेरिट करने के तरीके
कई तरीके हैं जिन्हें विरासत में लिया जा सकता है
public abstract class Car
{
public void HonkHorn() {
// Implementation of horn being honked
}
// virtual methods CAN be overridden in derived classes
public virtual void ChangeGear() {
// Implementation of gears being changed
}
// abstract methods MUST be overridden in derived classes
public abstract void Accelerate();
}
public class Mustang : Car
{
// Before any code is added to the Mustang class, it already contains
// implementations of HonkHorn and ChangeGear.
// In order to compile, it must be given an implementation of Accelerate,
// this is done using the override keyword
public override void Accelerate() {
// Implementation of Mustang accelerating
}
// If the Mustang changes gears differently to the implementation in Car
// this can be overridden using the same override keyword as above
public override void ChangeGear() {
// Implementation of Mustang changing gears
}
}
वंशानुक्रम विरोधी पैटर्न
अनुचित इनहेरिटेंस
बता दें कि 2 वर्ग वर्ग Foo
और Bar
। Foo
में दो फीचर्स Do1
और Do2
। Bar
को Foo
से Do1
का उपयोग करने की आवश्यकता है, लेकिन उसे Do2
आवश्यकता नहीं है या उसे ऐसी सुविधा की आवश्यकता है जो Do2
बराबर है Do2
लेकिन कुछ पूरी तरह से अलग है।
खराब तरीका : Do2()
को Foo
वर्चुअल करें और फिर इसे Bar
में ओवरराइड करें या Do2()
लिए Bar
में throw Exception
को Do2()
public class Bar : Foo
{
public override void Do2()
{
//Does something completely different that you would expect Foo to do
//or simply throws new Exception
}
}
अच्छा रास्ता
बाहर ले Do1()
से Foo
और नया वर्ग में डाल दिया Baz
दोनों इनहेरिट तो Foo
और Bar
से Baz
और लागू Do2()
अलग से
public class Baz
{
public void Do1()
{
// magic
}
}
public class Foo : Baz
{
public void Do2()
{
// foo way
}
}
public class Bar : Baz
{
public void Do2()
{
// bar way or not have Do2 at all
}
}
अब पहला उदाहरण खराब क्यों है और दूसरा अच्छा है: जब डेवलपर nr2 को Foo
में बदलाव करना है, तो संभावना है कि वह Bar
कार्यान्वयन तोड़ देगा क्योंकि Bar
अब Foo
से अविभाज्य है। इसे बाद के उदाहरण से करते हुए Foo
और Bar
सामान्यता को Baz
में ले जाया गया है और वे एक दूसरे को प्रभावित नहीं करते हैं (जैसे कि नहीं)।
पुनरावर्ती प्रकार विनिर्देशन के साथ बेस क्लास
पुनरावर्ती प्रकार विनिर्देशक के साथ एक सामान्य आधार वर्ग की एक बार परिभाषा। प्रत्येक नोड में एक माता-पिता और कई बच्चे हैं।
/// <summary>
/// Generic base class for a tree structure
/// </summary>
/// <typeparam name="T">The node type of the tree</typeparam>
public abstract class Tree<T> where T : Tree<T>
{
/// <summary>
/// Constructor sets the parent node and adds this node to the parent's child nodes
/// </summary>
/// <param name="parent">The parent node or null if a root</param>
protected Tree(T parent)
{
this.Parent=parent;
this.Children=new List<T>();
if(parent!=null)
{
parent.Children.Add(this as T);
}
}
public T Parent { get; private set; }
public List<T> Children { get; private set; }
public bool IsRoot { get { return Parent==null; } }
public bool IsLeaf { get { return Children.Count==0; } }
/// <summary>
/// Returns the number of hops to the root object
/// </summary>
public int Level { get { return IsRoot ? 0 : Parent.Level+1; } }
}
हर बार जब वस्तुओं की एक पेड़ पदानुक्रम को परिभाषित करने की आवश्यकता होती है, तो इसका इस्तेमाल किया जा सकता है। पेड़ में नोड ऑब्जेक्ट को बेस क्लास से विरासत में मिला है
public class MyNode : Tree<MyNode>
{
// stuff
}
प्रत्येक नोड वर्ग जानता है कि यह पदानुक्रम में कहां है, मूल वस्तु क्या है और साथ ही साथ बच्चों की वस्तुएं क्या हैं। कई प्रकार के निर्मित एक पेड़ की संरचना का उपयोग करते हैं, जैसे कि Control
या XmlElement
और उपरोक्त Tree<T>
का उपयोग आपके कोड में किसी भी प्रकार के आधार वर्ग के रूप में किया जा सकता है।
उदाहरण के लिए, उन हिस्सों का एक पदानुक्रम बनाने के लिए जहां कुल वजन की गणना सभी बच्चों के वजन से की जाती है, निम्नलिखित करें:
public class Part : Tree<Part>
{
public static readonly Part Empty = new Part(null) { Weight=0 };
public Part(Part parent) : base(parent) { }
public Part Add(float weight)
{
return new Part(this) { Weight=weight };
}
public float Weight { get; set; }
public float TotalWeight { get { return Weight+Children.Sum((part) => part.TotalWeight); } }
}
के रूप में इस्तेमाल किया जाएगा
// [Q:2.5] -- [P:4.2] -- [R:0.4]
// \
// - [Z:0.8]
var Q = Part.Empty.Add(2.5f);
var P = Q.Add(4.2f);
var R = P.Add(0.4f);
var Z = Q.Add(0.9f);
// 2.5+(4.2+0.4)+0.9 = 8.0
float weight = Q.TotalWeight;
एक अन्य उदाहरण रिश्तेदार समन्वय फ़्रेम की परिभाषा में होगा। इस मामले में समन्वय फ्रेम की सही स्थिति सभी माता-पिता समन्वय फ्रेम के पदों पर निर्भर करती है।
public class RelativeCoordinate : Tree<RelativeCoordinate>
{
public static readonly RelativeCoordinate Start = new RelativeCoordinate(null, PointF.Empty) { };
public RelativeCoordinate(RelativeCoordinate parent, PointF local_position)
: base(parent)
{
this.LocalPosition=local_position;
}
public PointF LocalPosition { get; set; }
public PointF GlobalPosition
{
get
{
if(IsRoot) return LocalPosition;
var parent_pos = Parent.GlobalPosition;
return new PointF(parent_pos.X+LocalPosition.X, parent_pos.Y+LocalPosition.Y);
}
}
public float TotalDistance
{
get
{
float dist = (float)Math.Sqrt(LocalPosition.X*LocalPosition.X+LocalPosition.Y*LocalPosition.Y);
return IsRoot ? dist : Parent.TotalDistance+dist;
}
}
public RelativeCoordinate Add(PointF local_position)
{
return new RelativeCoordinate(this, local_position);
}
public RelativeCoordinate Add(float x, float y)
{
return Add(new PointF(x, y));
}
}
के रूप में इस्तेमाल किया जाएगा
// Define the following coordinate system hierarchy
//
// o--> [A1] --+--> [B1] -----> [C1]
// |
// +--> [B2] --+--> [C2]
// |
// +--> [C3]
var A1 = RelativeCoordinate.Start;
var B1 = A1.Add(100, 20);
var B2 = A1.Add(160, 10);
var C1 = B1.Add(120, -40);
var C2 = B2.Add(80, -20);
var C3 = B2.Add(60, -30);
double dist1 = C1.TotalDistance;