Para os meus propósitos, gosto da ideia de @T-moty. Embora eu tenha usado informações de "tipo de autorreferência" por anos, referenciar a classe base é mais difícil de fazer mais tarde.
Por exemplo (usando o exemplo de @Rob Leclerc acima):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Trabalhar com esse padrão pode ser desafiador, por exemplo; como você retorna a classe base de uma chamada de função?
public Parent<???> GetParent() {}
Ou quando digitar o casting?
var c = (Parent<???>) GetSomeParent();
Portanto, tento evitá-lo quando posso e usá-lo quando preciso. Se necessário, sugiro que siga este padrão:
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) {}
}
Agora você pode (mais) trabalhar facilmente com o BaseClass
. No entanto, há momentos, como minha situação atual, em que expor a classe derivada, de dentro da classe base, não é necessário e usar a sugestão de @M-moty pode ser a abordagem certa.
No entanto, usar o código de @M-moty funciona apenas enquanto a classe base não contiver nenhum construtor de instância na pilha de chamadas. Infelizmente, minhas classes base usam construtores de instância.
Portanto, aqui está meu método de extensão que leva em consideração os construtores de 'instância' da 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;
}
}