Per i miei scopi, mi piace l'idea di @T-moty. Anche se ho usato per anni informazioni di "tipo autoreferenziale", fare riferimento alla classe base è più difficile da fare in seguito.
Ad esempio (usando l'esempio di @Rob Leclerc dall'alto):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Lavorare con questo modello può essere impegnativo, per esempio; come si restituisce la classe base da una chiamata di funzione?
public Parent<???> GetParent() {}
O quando digiti il casting?
var c = (Parent<???>) GetSomeParent();
Quindi, cerco di evitarlo quando posso e di usarlo quando devo. Se devi, ti suggerisco di seguire questo schema:
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) {}
}
Ora puoi (più) facilmente lavorare con BaseClass
. Tuttavia, ci sono momenti, come la mia situazione attuale, in cui non è necessario esporre la classe derivata, dall'interno della classe base, e usare il suggerimento di @ M-moty potrebbe essere l'approccio giusto.
Tuttavia, l'utilizzo del codice di @ M-moty funziona solo fintanto che la classe base non contiene alcun costruttore di istanza nello stack di chiamate. Purtroppo le mie classi base utilizzano costruttori di istanze.
Pertanto, ecco il mio metodo di estensione che tiene conto dei costruttori di "istanza" della classe base:
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;
}
}