Đối với mục đích của tôi, tôi thích ý tưởng của @ T-moty. Mặc dù tôi đã sử dụng thông tin "kiểu tự tham chiếu" trong nhiều năm, việc tham chiếu lớp cơ sở sau này khó thực hiện hơn.
Ví dụ (sử dụng ví dụ @Rob Leclerc ở trên):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
Ví dụ, làm việc với mẫu này có thể khó khăn; làm thế nào để bạn trả về lớp cơ sở từ một lời gọi hàm?
public Parent<???> GetParent() {}
Hoặc khi loại đúc?
var c = (Parent<???>) GetSomeParent();
Vì vậy, tôi cố gắng tránh nó khi tôi có thể, và sử dụng nó khi tôi phải. Nếu bạn bắt buộc phải làm, tôi khuyên bạn nên làm theo mẫu sau:
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) {}
}
Bây giờ bạn có thể (nhiều hơn) dễ dàng làm việc với BaseClass
. Tuy nhiên, có những lúc, giống như tình huống hiện tại của tôi, việc hiển thị lớp dẫn xuất, từ bên trong lớp cơ sở, là không cần thiết và sử dụng gợi ý của @ M-moty có thể là cách tiếp cận phù hợp.
Tuy nhiên, việc sử dụng mã của @ M-moty chỉ hoạt động miễn là lớp cơ sở không chứa bất kỳ hàm tạo cá thể nào trong ngăn xếp cuộc gọi. Thật không may, các lớp cơ sở của tôi sử dụng các hàm tạo cá thể.
Do đó, đây là phương thức mở rộng của tôi có tính đến các hàm tạo 'phiên bản' của lớp cơ sở:
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;
}
}