Für meine Zwecke mag ich die Idee von @ T-moty. Obwohl ich seit Jahren Informationen zum Typ "Selbstreferenzierend" verwende, ist es später schwieriger, auf die Basisklasse zu verweisen.
Zum Beispiel (am Beispiel von @Rob Leclerc von oben):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Das Arbeiten mit diesem Muster kann beispielsweise eine Herausforderung sein. Wie gibt man die Basisklasse von einem Funktionsaufruf zurück?
public Parent<???> GetParent() {}
Oder beim Typguss?
var c = (Parent<???>) GetSomeParent();
Also versuche ich es zu vermeiden, wenn ich kann, und benutze es, wenn ich muss. Wenn Sie müssen, würde ich vorschlagen, dass Sie diesem Muster folgen:
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) {}
}
Jetzt können Sie (einfacher) mit dem arbeiten BaseClass. Es gibt jedoch Zeiten wie in meiner aktuellen Situation, in denen es nicht erforderlich ist, die abgeleitete Klasse innerhalb der Basisklasse verfügbar zu machen, und die Verwendung des Vorschlags von @ M-moty möglicherweise der richtige Ansatz ist.
Die Verwendung des Codes von @ M-moty funktioniert jedoch nur, solange die Basisklasse keine Instanzkonstruktoren im Aufrufstapel enthält. Leider verwenden meine Basisklassen Instanzkonstruktoren.
Daher hier meine Erweiterungsmethode, die Instanzkonstruktoren der Basisklasse berücksichtigt:
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;
}
}