Получить тип производного класса из статического метода базового класса - PullRequest
19 голосов
/ 17 июня 2010

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

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

Спасибо!

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();

Ответы [ 8 ]

35 голосов
/ 19 ноября 2011

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

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();

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

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

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

14 голосов
/ 17 июня 2010

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

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

Вы бы назвали это так:

BaseClass.Ping<DerivedClass>();
4 голосов
/ 17 июня 2010

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

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();
3 голосов
/ 11 мая 2011

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

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's static method through DerivedClass
        //and it will know what Type calls it
        DerivedClass.Ping();    
    }
}
0 голосов
/ 28 июля 2013

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

Создайте трассировку стека и проанализируйте ее в поисках производного класса.В общем случае это не будет слишком надежно или даже может не сработать, но , в определенных случаях , как в 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 будет только один элемент, но это будет зависеть от особенностей приложения.Некоторые эксперименты будут необходимы.

0 голосов
/ 17 июня 2010

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

Если у вас есть

class BaseClass {}
partial class DerivedClass : BaseClass {}

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

DerivedClass.GetType().BaseType;
0 голосов
/ 17 июня 2010

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

Type t = MethodBase.GetCurrentMethod().DeclaringType;
0 голосов
/ 17 июня 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...