Получить тип производного класса из статического метода базового класса
Мне хотелось бы получить тип производного класса из статического метода его базового класса.
Как это можно сделать?
Спасибо!
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();
Ответы
Ответ 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 будет только один элемент, но он будет зависеть от особенностей приложения. Некоторые эксперименты потребуются.