在自引用类,泛型类,静态构造函数

时间:2016-04-30 18:54:14

标签: c# generics

好吧,这不是一个简单的问题,代码可以帮助我解释这个问题。

我需要的是一种在自引用类,泛型类,静态构造函数中获取类类型的方法

想象一下,你有这样的代码:

public class ClassA : BaseClass<ClassA>{
}
public abstract class BaseClass<T> where T : BaseClass<T> {
    static readonly int _aValue;
    static BaseClass(){
       //here i have code that load _avalue for each kind of T type, based on my own logic
       _aValue=1;

       //need to get the real type here
    }
    public int GetValue() {
       return _aValue;
    }
}


ClassA c = new ClassA();
Console.WriteLine(c.GetValue());

然后当你做

之类的事情
ClassA c = new ClassA();
Console.WriteLine(c.GetValue());

这里发生的是静态构造函数被调用,并且在我的示例中将值加载到静态变量

我需要在静态构造函数中知道,如果调用构造函数的类型(在泛型类型构造函数中,每个派生类调用它,所以我假设我可以做我需要的)如果T类型实际上是ClassA

我真正的需要是知道我是否正确地声明了我的类定义,因为我没有找到一种很好的方法来确保自引用类型是真正的自引用,因为在我的测试中我发现

ClassX : Message<ClassAAA>

在我想强制执行时不会出现错误

ClassA : Message<ClassA>
ClassB : Message<ClassB>
ClassC : Message<ClassC>

而不是

ClassD : Message<DifferentClass>

任何线索?

我已经尝试过使用MethodInfo.GetMethod()。DeclaringType但它返回基类

更新 好的,让我试着解释一下 在我的场景中,我使用这种设计来获得我在客户端/服务器场景中使用的自定义消息定义,并且每个不同的消息派生类必须有一个指定“消息ID”的字节,所以我使用属性来装饰我的类并且该属性允许我指定枚举值(所以我没有代码周围的幻数)

在我的Message基类的静态构造函数中,我使用反射来读取属性值并将其存储到其静态_aValue成员中,因此每种消息都有自己的消息ID,并且每个消息类型只加载一次,并且出于性能原因,不是在实例构造函数中。 它运作得很好,我可以说像

这样的课程
[MyAttribute(MyMessages.Ping)]
public class PingMessage : Message<PingMessage>

每当我的PingMessage类被实现时,我都可以得到它的静态messageTye值,我对此很满意,问题是有时会因为错误而发生,我会创建一个像

这样的类
[MyAttribute(MyMessages.Ping)]
public class PingMessage : Message<AnotherMessage>

并且泛型约束不会引起编译时错误,因为AnotherMessage是继承自Message的另一个类,因此它是合法的,但我想强制执行,如果从Message继承,则T必须是继承的类,所以只是允许

PingMessage : Message<PingMessage>

我知道没有通用约束允许我这样做,我当然不能在约束中添加派生类,因为我不知道我将创建哪些消息(并且无论如何都有很多消息它没有意义)所以我想在消息类型的静态构造函数中做我的类型约束检查,因为我已经在那里做了一些事情,所以在我看来最好放我的支票,上升如果类型没有错误或类没有指定属性

,则为例外

我在技术上可以在我的实例构造函数中进行这种检查,但性能很重要所以我不能。

我想过让我的Message实现一个自定义接口然后有一个接口的方法来检查类型,并且只在初始化期间调用它,但我想找到一个更简单的方法,如果可能,但似乎反射可以'帮帮我

2 个答案:

答案 0 :(得分:0)

我不知道如何阻止class X : Message<Y>被声明,但您可以将Message子类型的使用仅限于您想要的那些。

R Foo<A>(A a) where A : Message<A>
{
  // …
}

如果使用类型反射,则只能在运行时知道您的程序是否有效。目标是可以由编译器检查的解决方案。

答案 1 :(得分:0)

在第一次访问基类时调用基类的静态构造函数。这不必是派生类实例化,例如,在基类上调用静态方法时。派生类与基类的静态构造函数无关。也不可能,因为多个类可以从相同的通用基类派生。

派生类实例化是基类可以知道您正在处理哪个派生类的最早时间。您可以在非静态基类构造函数中测试对象的运行时类型:if (!typeof(T).IsAssignableFrom(this.GetType())) throw new InvalidOperationException();。当然,缺点是它在编译时没有被捕获。