В моих целях мне нравится идея @ T-moty. Несмотря на то, что я годами использовал информацию о «типе самоссылки», ссылаться на базовый класс сложнее позже.
Например (используя пример @Rob Leclerc, приведенный выше):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Работа с этим шаблоном может быть сложной, например; как вы возвращаете базовый класс из вызова функции?
public Parent<???> GetParent() {}
Или когда типа литья?
var c = (Parent<???>) GetSomeParent();
Итак, я стараюсь избегать этого, когда могу, и использую, когда должен. Если вам нужно, я бы посоветовал вам следовать этой схеме:
class BaseClass
{
// All non-derived class methods goes here...
// For example:
public int Id { get; private set; }
public string Name { get; private set; }
public void Run() {}
}
class BaseClass<TSelfReferenceType> : BaseClass
{
// All derived class methods goes here...
// For example:
public TSelfReferenceType Foo() {}
public void Bar(TSelfRefenceType obj) {}
}
Теперь вы можете (более) легко работать с BaseClass
. Однако бывают случаи, как в моей нынешней ситуации, когда предоставление производного класса из базового класса не требуется, и использование предложения @ M-moty может быть правильным подходом.
Однако использование кода @ M-moty работает только до тех пор, пока базовый класс не содержит конструкторов экземпляров в стеке вызовов. К сожалению, мои базовые классы используют конструкторы экземпляров.
Поэтому, вот мой метод расширения, который учитывает конструкторы экземпляра базового класса:
public static class TypeExtensions
{
public static Type GetDrivedType(this Type type, int maxSearchDepth = 10)
{
if (maxSearchDepth < 0)
throw new ArgumentOutOfRangeException(nameof(maxSearchDepth), "Must be greater than 0.");
const int skipFrames = 2; // Skip the call to self, skip the call to the static Ctor.
var stack = new StackTrace();
var maxCount = Math.Min(maxSearchDepth + skipFrames + 1, stack.FrameCount);
var frame = skipFrames;
// Skip all the base class 'instance' ctor calls.
//
while (frame < maxCount)
{
var method = stack.GetFrame(frame).GetMethod();
var declaringType = method.DeclaringType;
if (type.IsAssignableFrom(declaringType))
return declaringType;
frame++;
}
return null;
}
}