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;
}
}