Передать текущий тип объекта в вызов базового конструктора - PullRequest
9 голосов
/ 18 февраля 2010

Как мне получить Type унаследованного класса и передать его в базовый конструктор класса, также унаследованного? Смотрите пример кода ниже:

// 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 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)
    {

    }
}

Строка base(typeof(this).Name, myObject) не работает, потому что я пока не могу сослаться на this, так как объект не закончил конструирование и поэтому не существует.

Можно ли получить Type текущего строящегося объекта?

EDIT:

Исправил образец, как orsogufo предложил , но все равно не работает, так как this не определено.

РЕДАКТИРОВАТЬ 2:

Просто чтобы прояснить, я хочу в итоге передать "InheritedClass" в конструктор VeryBaseClass(string className, MyObject myObject).

Ответы [ 6 ]

18 голосов
/ 26 февраля 2010

Ах, ха! Я нашел решение. Вы можете сделать это с помощью дженериков:

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

    }
}
6 голосов
/ 18 февраля 2010

Раньше у меня была точно такая же боль в Google Wave Robot .NET API , где я хотел, чтобы конструктор передавал некоторые значения на основе атрибутов. Вы можете взглянуть на мое решение в коде для производного типа и базового типа . По сути, я передаю делегат базовому конструктору, а затем вызываю этот делегат, передавая делегату слово «this». Так что в вашем случае у вас будет:

public VeryBaseClass(Func<VeryBaseClass, string> classNameProvider)
{
    this.name = classNameProvider(this);
}

и

public BaseClass() : base(FindClassName)
{
}

private static string FindClassName(VeryBaseClass @this)
{
    return @this.GetType().Name;
}

Это действительно ужасно, но это работает.

РЕДАКТИРОВАТЬ: Этот подход работает, только если вы можете изменить конструктор базового класса, как показано; если вы не можете, я не уверен, что это вообще возможно: (

3 голосов
/ 22 февраля 2010

Если возможность определить тип унаследованного класса во время выполнения более важна, чем производительность, вы можете взглянуть на StackTrace, чтобы узнать, откуда вызывается конструктор.При вызове GetInheritedClassName в этом примере вам может потребоваться написать больше предположений:

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

    }
}

Я не могу придумать отличный способ динамически получить имя унаследованного класса без влияния на производительность.Я понимаю, что вы хотели избежать, но если бы мне нужно было вызывать стороннюю сборку с этими требованиями, я бы просто потребовал, чтобы каждый класс указывал свой собственный тип:

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

    }
}
3 голосов
/ 18 февраля 2010

Возможное решение:

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();
    }
}
3 голосов
/ 18 февраля 2010

Не работает ли GetType (). Name?

0 голосов
/ 18 февраля 2010

Еще один вариант ...

// 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)
    {
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...