I'm looking for the best way to provide a method in an (abstract) base class, which all inheriting classes should be able to use.
This method needs to reference fields and properties of the inheriting types.
Is there a way to provide such a prototype method which doesn't require me to either:
- Pass a reference to each inheriting instance in question
- Implement a method on each inheriting class which passes a reference to itself to the base class's method
- Write an extension method for implementing classes
All of the above work, but seem somewhat inconvenient and unelegant in their own way.
Here is an example where I implemented the three above methods of referencing the inheriting class:
using System;
namespace Test
{
public abstract class BaseClass
{
public void ReferenceInheriting(object InheritingInstance)
{
Console.WriteLine("Do things specific to the inheriting class or instance thereof: " InheritingInstance.GetType().Name);
}
}
public class Inheriting : BaseClass
{
public void MakeUseOfBaseClassImplementation()
{
base.ReferenceInheriting(this);
}
}
public static class Extensions
{
public static void BeAvailableForAllImplementing(this BaseClass Inh)
{
Console.WriteLine("Do things specific to the inheriting class or instance thereof: " Inh.GetType().Name);
}
}
class program
{
public static void Main(string[] args)
{
Inheriting inh = new Inheriting();
Console.WriteLine("Method 1: Calling the inherited method from an inheriting instance, passing a reference to the instance:");
inh.ReferenceInheriting(inh);
Console.WriteLine("Method 2: Implementing call to the base class's method in own class:");
inh.MakeUseOfBaseClassImplementation();
Console.WriteLine("Method 3: Extension method for all implementing classes:");
inh.BeAvailableForAllImplementing();
}
}
}
The three approaches all produce the same output, but have drawbacks.
Short of parsing caller information, is there another way to do this?
It's not a big deal of course, but I'm interested in making this method as user friendly as possible, both for implementing inheritance and for calling.
Thank you!
CodePudding user response:
You don't need any of that.
This:
public void reflectInheriting(object inheritingInstance)
{
Console.WriteLine("Do things specific to the inheriting class or instance thereof: " inheritingInstance.GetType().Name);
FieldInfo fi = inheritingInstance.GetType().GetField("getMe");
Console.WriteLine(fi.GetValue(inheritingInstance));
}
Can be rewritten as simply:
public void reflectInheriting()
{
Console.WriteLine("Do things specific to the inheriting class or instance thereof: " this.GetType().Name);
FieldInfo fi = this.GetType().GetField("getMe");
Console.WriteLine(fi.GetValue(this));
}
And that's all you need.
C# saves the actual underlying type of an object regardless of how it's cast, so even inside BaseClass
, this.GetType()
will be Inheriting
.
Program output to prove nothing has changed:
Method 1: Calling the inherited method from an inheriting instance, passing a reference to the instance:
Do things specific to the inheriting class or instance thereof: Inheriting
Use me in BaseClass
Method 2: Implementing call to the base class's method in own class:
Do things specific to the inheriting class or instance thereof:
InheritingUse me in BaseClass
Method 3: Extension method for all implementing classes:
Do things specific to the inheriting class or instance thereof: Inheriting
Use me in BaseClass
CodePudding user response:
You could use Reflection, but that is kind of a weapon of last resort. The idiomatic way to access a property or method in a descendent class is to make it abstract in the base class.
public abstract class BaseClass
{
public void GetInheriting()
{
Console.WriteLine("GetMe is: {0}", this.GetMe);
}
protected abstract string GetMe { get; }
}
public class Inheriting : BaseClass
{
protected override string GetMe => "Use me in BaseClass";
public void MakeUseOfBaseClassImplementation()
{
base.GetInheriting();
}
}
public class Program
{
static public void Main()
{
var o = new Inheriting();
o.MakeUseOfBaseClassImplementation();
}
}
Output:
GetMe is: Use me in BaseClass