Подтвердить что ты не робот

Получить тип производного класса из статического метода базового класса

Мне хотелось бы получить тип производного класса из статического метода его базового класса.

Как это можно сделать?

Спасибо!

class BaseClass {
  static void Ping () {
     Type t = this.GetType(); // should be DerivedClass, but it is not possible with a static method
  }
}
class DerivedClass : BaseClass {}

// somewhere in the code
DerivedClass.Ping();
4b9b3361

Ответ 1

Если я не ошибаюсь, код, испущенный для BaseClass.Ping() и DerivedClass.Ping(), будет таким же, поэтому статический метод, не дающий никаких аргументов, не будет работать. Попробуйте передать тип в качестве аргумента или через общий тип типа (на котором вы можете принудительно установить ограничение наследования).

class BaseClass {
    static void Ping<T>() where T : BaseClass {
        Type t = typeof(T);
    }
}

Вы бы назвали это следующим образом:

BaseClass.Ping<DerivedClass>();

Ответ 2

Это можно легко выполнить с помощью любопытно повторяющегося шаблона шаблона

class BaseClass<T>
    where T : BaseClass<T>
{
    static void SomeMethod() {
        var t = typeof(T);  // gets type of derived class
    }
}

class DerivedClass : BaseClass<DerivedClass> {}

вызов метода:

DerivedClass.SomeMethod();

Это решение добавляет небольшое количество служебных надбавок, потому что вам необходимо создать шаблон базового класса с производным классом.

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

И по шаблонам я, конечно, имею в виду дженерики.

Ответ 3

Статический метод определяется типом. Нет "this". Вам нужно будет сделать это методом экземпляра, вместо этого:

class BaseClass {
    public void Ping() {
        Type t = this.GetType(); // This will work, since "this" has meaning here...
    }

Затем вы можете:

class DerivedClass : BaseClass {}

DerivedClass instance = new DerivedClass();
instance.Ping();

Ответ 4

Короче, вот что я пытался ответить здесь. Он использует один интерфейс для унификации всех производных классов и позволяет всем им вызвать один и тот же статический метод из базового класса без передачи типа.

public interface IDerived
{
}
public class BaseClass<T> where T : IDerived
{
    public static void Ping()
    {
        //here you have T = the derived type
    }
}
public class DerivedClass : BaseClass<DerivedClass>, IDerived
{
    //with : BaseClass<DerivedClass> we are defining the T above
}
public class ExampleApp
{
    public void Main()
    {
        //here we can call the BaseClass static method through DerivedClass
        //and it will know what Type calls it
        DerivedClass.Ping();    
    }
}

Ответ 5

Невозможно получить производный класс из статического метода. В качестве примера, чтобы проиллюстрировать, почему, представьте, что BaseClass имеет 2 подкласса - DerivedClass и AnotherDerivedClass - какой из них нужно вернуть? В отличие от полиморфных нестатических методов нет никакой связи с производным классом, вызывающим статический метод в базовом классе - тип времени компиляции и тип времени выполнения одинаковы со статическим вызовом метода.

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

class DerivedClass : BaseClass
{
   void Ping() { 
     BaseClass.Ping();
     // or alternatively
     BaseClass.Ping(Type.GetType("DerivedClass"));
   }
}

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

Ответ 6

Просто предположение (не проверено)

Type t = MethodBase.GetCurrentMethod().DeclaringType;

Ответ 7

Почему бы просто не использовать уже существующие методы?

Если у вас

class BaseClass {}
partial class DerivedClass : BaseClass {}

Вы можете посмотреть

DerivedClass.GetType().BaseType;

Ответ 8

Я думаю, что для этого случая будет работать следующее (и несколько подобных в другом месте на SO). Перф не будет слишком хорош, но если это нечасто, это не будет проблемой.

Создайте stacktrace и проанализируйте его поиск производного класса. В общем случае это не было бы слишком надежным или даже не работало, но в конкретных случаях, как в OP, я считаю, что это будет работать нормально. В Powershell:

$strace = (new-object diagnostics.stacktrace).tostring()
#
$frames = $strace -split "   at "
$typesFromFrames = $frames | select -skip 1| # skip blank line at the beginning
   % { ($_ -split "\(",2)[0]} |                 # Get rid of parameters string
   % {$_.substring(0,$_.lastindexof("."))} |    # Get rid of method name
   $ {$_ -as [type]}
#
# In powershell a lot of the frames on the stack have private classes
#  So $typesFromFrames.count is quite a bit smaller than $frames.count
#  For the OP, I don't think this will be a problem because:
#   1. PS isn't being used
#   2. The derived class in the OP isn't private 
#        (if it is then tweaks will be needed)
#
$derivedOnStack = $typesFromFrames | ? { $_.issubclassof( [BaseClass])}

Надеюсь, что в $outputOnStack будет только один элемент, но он будет зависеть от особенностей приложения. Некоторые эксперименты потребуются.