Dla moich celów podoba mi się pomysł @ T-moty. Mimo że od lat korzystam z informacji o „typach odwołań do samych siebie”, późniejsze odniesienie do klasy bazowej jest trudniejsze.
Na przykład (używając przykładu @Rob Leclerc z góry):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Na przykład praca z tym wzorcem może być trudna; jak zwrócić klasę bazową z wywołania funkcji?
public Parent<???> GetParent() {}
Albo podczas castingu?
var c = (Parent<???>) GetSomeParent();
Dlatego staram się tego unikać, kiedy mogę, i używać tego, kiedy muszę. Jeśli musisz, proponuję postępować zgodnie z tym wzorem:
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) {}
}
Teraz możesz (bardziej) łatwiej pracować z BaseClass
. Jednak są chwile, tak jak moja obecna sytuacja, kiedy ujawnianie klasy pochodnej z klasy bazowej nie jest potrzebne i użycie sugestii @ M-moty może być właściwym podejściem.
Jednak użycie kodu @ M-moty działa tylko wtedy, gdy klasa bazowa nie zawiera żadnych konstruktorów instancji na stosie wywołań. Niestety moje klasy bazowe używają konstruktorów instancji.
Dlatego oto moja metoda rozszerzenia uwzględniająca konstruktory instancji klasy bazowej:
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;
}
}