Для моїх цілей мені подобається ідея @ 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 працює лише до тих пір, поки базовий клас не містить конструкторів екземплярів у стеку викликів. На жаль, мої базові класи використовують конструктори екземплярів.
Отже, ось мій метод розширення, який враховує конструктори базового класу 'instance':
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;
}
}