One of the major goals of OOP inheritance ... you can call it by various names, like: "modeling real-world objects and processes," "separation of concerns," "loose coupling," etc. ... is allowing a flexible structuring of what all objects
share (what they inherit), and what any individual child object, or group of the same type child object implements, or defines, or overrides,
separately from what they inherit.
.NET implements single-inheritance for Classes, and, through Interfaces, allows a
very limited type of multiple-inheritance.
Within a Class that inherits, you can use the special operator "base" to access public fields and methods of the Class you inherit from. Note that "base," used as part of the Constructor Method definition (ctor) in a derived Class has a very different function.
Most of the time, imho, you'll be fine if you learn about basic Class inheritance, the use of Abstract Classes, and Interfaces, the use of the 'new and 'override keywords, and the special ancestor-accessor keyword "base" in derived Classes. And, you can round that out by learning how to use static classes, and, if absolutely necessary, static fields, or methods, inside dynamic classes.
I am not sure what follows is "the right thing," since it exposes you to some esoteric use-cases of inheritance in .NET, but I can't resist showing how, in fact, a base Class
could keep track of its derived, or child, Classes. At the risk of taking you on a "dizzying" roller-coaster ride:
using System;
using System.Collections.Generic;
namespace Dec25_InheritanceTest
{
public class ParentClass
{
public int theInt = 500;
public string theString = "some text";
public static List<ParentClass> theChildren = new List<ParentClass>();
public void showValues()
{
Console.WriteLine();
Console.WriteLine("in ParentClass");
Console.WriteLine(theInt.ToString());
Console.WriteLine(theString);
Console.WriteLine("ParentClass has " + theChildren.Count.ToString() + " child classes:");
foreach (ParentClass child in theChildren)
{
Console.WriteLine("\tClass: " + child.GetType().Name);
}
Console.WriteLine();
}
}
public class ChildClass1 : ParentClass
{
public new int theInt;
public new string theString;
public int ChildClass1Int = 333;
public ChildClass1() {}
public ChildClass1(int theint, string thestring)
{
theInt = theInt;
theString = thestring;
ParentClass.theChildren.Add(this);
base.theInt = 999;
}
public void showValues()
{
Console.WriteLine();
Console.WriteLine("in child1 Class");
Console.WriteLine(theInt.ToString());
Console.WriteLine(theString);
Console.Write("in ChildClass1Int = ");
Console.WriteLine(ChildClass1Int);
Console.WriteLine();
base.showValues();
}
}
public class ChildClass2 : ChildClass1
{
public new int theInt;
public new string theString;
public ChildClass2(int theint, string thestring) : base()
{
theInt = theint;
theString = thestring;
ParentClass.theChildren.Add(this);
base.theInt = 777;
base.ChildClass1Int = 222;
}
public void showValues()
{
Console.WriteLine();
Console.WriteLine("in child2 Class");
Console.WriteLine(theInt.ToString());
Console.WriteLine(theString);
Console.Write("in ChildClass1Int = ");
Console.WriteLine(base.ChildClass1Int);
Console.WriteLine();
base.showValues();
}
}
}
At this point, I invited you to execute this code in a C# Project where you have implemented the above Class definitions:
private void TestEsotericInheritance()
{
ChildClass1 child1 = new ChildClass1(1,"child 1");
child1.showValues();
ChildClass2 child2 = new ChildClass2(2, "child 2");
child2.showValues();
}
And put a break-point on each line, and single-step when you hit the break-point using <f11> and inspect the internal values as you watch what happens. Then examine the output in the Output Window of VS.
To me the most interesting aspect of this demonstration is that this code "works" without ever formally creating an instance of the ParentClass. You could also execute the line of code:
ChildClass2 child2 = new ChildClass2(2, "child 2");
by itself, and see that it also "works" without ever having created an instance of ChildClass1 !
So, I'd like to challenge you to infer what's happening in .NET when we can, apparently, get access to, and use, fields of Classes that are
not static, and have no instances created. I'd call this a kind of "optical illusion" of .NET.
So, what's the point of this excursion into what's possible with inheritance in .NET ? imho: to be aware that such functionality is there ... if you require it ... and, to understand how the most typical uses of .NET's inheritance work, and that such typical uses may not require such functionality.
If you care to, please let me know if you think this type of example is useful, or: if it's just: distracting. I can live, half-comfortably, with the possibility that: while it may be valuable for me to regurgitate the digested remains of a several-year journey in C#, it may not be valuable to you :)