开发者

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)
    {
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜