Pass current object type into base constructor call
How do I grab the Type
of the inherited class and pass it into the base constructor of the class also inherited? See the code sample below:
// VeryBaseClass is in an external assembly
public abstract class VeryBaseClass
{
public VeryBaseClass(string className, MyObject myObject)
{
}
}
// BaseClass and InheritedClass are in my assembly
public abstract 开发者_JAVA技巧class BaseClass : VeryBaseClass
{
public BaseClass(MyObject myObject) :
base(this.GetType().Name, myObject) // can't reference "this" (Type expected)
{
}
}
public class InheritedClass : BaseClass
{
public InheritedClass(MyObject myObject)
{
}
}
The line base(typeof(this).Name, myObject)
doesn't work because I can't reference this
yet, as the object hasn't finished constructing and therefore doesn't exist.
Is it possible to grab the Type
of the currently constructing object?
EDIT:
Corrected the sample as orsogufo suggested, but still doesn't work, as this
is undefined.
EDIT 2:
Just to clarify, I want to end up with "InheritedClass"
being passed into the VeryBaseClass(string className, MyObject myObject)
constructor.
Ah Hah! I found a solution. You can do it with generics:
public abstract class VeryBaseClass
{
public VeryBaseClass(string className, MyObject myObject)
{
this.ClassName = className;
}
public string ClassName{ get; set; }
}
public abstract class BaseClass<T> : VeryBaseClass
{
public BaseClass(MyObject myObject)
: base(typeof(T).Name, myObject)
{
}
}
public class InheritedClass : BaseClass<InheritedClass>
{
public InheritedClass(MyObject myObject)
: base(myObject)
{
}
}
I've had exactly the same pain before now in the Google Wave Robot .NET API where I wanted to make the constructor pass in some values based on attributes. You can have a look at my solution in the code for the derived type and the base type. Basically I pass a delegate to the base constructor, and then call that delegate passing in "this" to the delegate. So in your case you'd have:
public VeryBaseClass(Func<VeryBaseClass, string> classNameProvider)
{
this.name = classNameProvider(this);
}
and
public BaseClass() : base(FindClassName)
{
}
private static string FindClassName(VeryBaseClass @this)
{
return @this.GetType().Name;
}
It's really ugly, but it works.
EDIT: This approach only works if you can change your base class constructor as shown; if you can't, I'm not sure it's actually feasible at all :(
Does GetType().Name not work?
A possible solution:
class VeryBase {
public VeryBase(string name) {
Console.WriteLine(name);
}
}
class Base<T> : VeryBase where T : Base<T> {
protected Base()
: base(typeof(T).Name) {
}
}
class Derived : Base<Derived> {
public Derived() {
}
}
class Program {
public static void Main(params string[] args) {
Derived d = new Derived();
}
}
If the ability to determine the inherited class's type at runtime is more important than performance you can take a look at the StackTrace to see where the constructor is being called from. You may need to code in more assumptions when calling GetInheritedClassName in this example:
public abstract class BaseClass : VeryBaseClass
{
private static string GetInheritedClassName
{
get
{
// Get the current Stack
StackTrace currentStack = new StackTrace();
MethodBase method = currentStack.GetFrame(1).GetMethod();
// 1st frame should be the constructor calling
if (method.Name != ".ctor")
return null;
method = currentStack.GetFrame(2).GetMethod();
// 2nd frame should be the constructor of the inherited class
if (method.Name != ".ctor")
return null;
// return the type of the inherited class
return method.ReflectedType.Name;
}
}
public BaseClass(MyObject myObject) :
base(GetInheritedClassName, myObject)
{
}
}
I cannot think of a great way to dynamically get the name of the inherited class without performance implications. I realize is what you wanted to avoid but if I needed to call a 3rd party assembly with these requirements I would just require each class to specify its own type:
public abstract class BaseClass : VeryBaseClass
{
public BaseClass(string className, MyObject myObject) :
base(className, myObject)
{
}
}
public class InheritedClass : BaseClass
{
public InheritedClass(MyObject myObject) : base("InheritedClass", myObject)
{
}
}
Yet another option...
// VeryBaseClass is in an external assembly
public abstract class VeryBaseClass
{
public VeryBaseClass(string className)
{
Console.WriteLine(className);
}
}
// BaseClass and InheritedClass are in my assembly
public abstract class BaseClass : VeryBaseClass
{
public BaseClass(string className)
:
base(className)
{
}
}
public class InheritedClass : BaseClass
{
public InheritedClass()
: base(typeof(InheritedClass).Name)
{
}
}
精彩评论