खोज…


वाक्य - विन्यास

  • वर्ग 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 क्लास कंस्ट्रक्टर होता है; फिर श्रृंखला में अगले निर्माता को बुलाया जाता है और केवल उन सभी को बुलाया जाता है, जिसके बाद वस्तु बनाई जाती है

आधार कीवर्ड

  1. बेस कीवर्ड का उपयोग बेस क्लास के सदस्यों को एक व्युत्पन्न वर्ग के भीतर से एक्सेस करने के लिए किया जाता है:
  2. बेस क्लास पर एक विधि को कॉल करें जिसे किसी अन्य विधि द्वारा ओवरराइड किया गया है। यह निर्दिष्ट करें कि व्युत्पन्न वर्ग के उदाहरण बनाते समय किस बेस-क्लास कंस्ट्रक्टर को बुलाया जाना चाहिए।

इनहेरिट करने के तरीके

कई तरीके हैं जिन्हें विरासत में लिया जा सकता है

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 और BarFoo में दो फीचर्स Do1 और Do2Bar को 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;


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow