如何触发静态构造函数
代码:
class Base<T,U> where T:Base<T,U>,new() where U :class
{
protected static U _val = null;
internal static void ShowValue()
{
if(_val == null)new T(); //Without this line, it won't work as expected
Console.WriteLine (_val);
}
internal static void Virtual()
{
Console.WriteLine ("Base");
}
}
class Deriv :Base<Deriv,string>
{
static Deriv()
{
_val = "some string value";
}
internal static new void Virtual ()
{
Console.WriteLine ("Deriv");
}
}
public static void Main (string[] args)
{
Deriv.ShowValue();
Deriv.Virtual();
}
感谢 .NET 的泛型,我可以使用泛型基类中定义的泛型静态方法创建一堆特定的类。它可以在一定程度上模仿继承多态性。但为了初始化不同版本的静态字段,我必须使用静态构造函数。不幸的是,我们不能直接调用它们,因此,我们必须找到一种方法来触发它的调用。上面给出的例子展示了一种方法。但我不喜欢实例化或反射方法。我们也无法对泛型参数的静态方法进行约束。所以我想问一下,是否还有其他方法可以完成这种工作!
预先感谢!
~~~~~~~~~~~~~~~~
一些结论(也许有点早):
似乎没有解决方法来处理这种情况。我必须实例化一个子类或使用反射。考虑到 .cctors 只需要调用一次,我赞成反射方法,因为在某些情况下, new() 约束不是一个选择 - 就像您不应该向用户公开无参数 ctor 一样。
经过进一步的实验,我发现.cctors可能被多次调用,但只有第一次调用才会影响静态字段的设置。这很奇怪,但却是一个很好的奇怪!
class MyClass
{
static int _val = 0;
static MyClass()
{
_val++;
Console.WriteLine (_val);
}
}
public static void Main (string[] args)
{
ConstructorInfo ci = typeof(MyClass).TypeInitializer;
ci.Invoke(new object[0]);
ci.Invoke(new object[0]);
ci.Invoke(new object[0]);
}
//result:
//1
//1
//1
//1
code:
class Base<T,U> where T:Base<T,U>,new() where U :class
{
protected static U _val = null;
internal static void ShowValue()
{
if(_val == null)new T(); //Without this line, it won't work as expected
Console.WriteLine (_val);
}
internal static void Virtual()
{
Console.WriteLine ("Base");
}
}
class Deriv :Base<Deriv,string>
{
static Deriv()
{
_val = "some string value";
}
internal static new void Virtual ()
{
Console.WriteLine ("Deriv");
}
}
public static void Main (string[] args)
{
Deriv.ShowValue();
Deriv.Virtual();
}
Thanks to the generics of .NET, I can create a bunch of specific classes reusing generic static methods defined in the generic base class. It can mimic inheritance polymorphism to some extent. But in order to initialize different version of static fields, I've to use static constructors. Unfortunately, we can't call them directly, therefore, we have to figure out a way to trigger it's invocation. The example given above showed a way. But I don't like either the instantiation,or the reflection approach. We also can't make a constraint on a static method of a generic parameter. So, I'd like to ask, if there is another way to do this kind of job!
Thanks beforehand!
~~~~~~~~~~~~~~~~
Some Conclusion (Maybe a little early):
It seems there is no workaround to deal with this kind of situation. I have to instantiate a subclass or use reflection. Considering the .cctors need merely be called once, I'm in favor of the reflection approach, because in some case, a new() constraint is just not a choice - like you're not supposed to expose the parameterless ctor to user.
After conducting further experiment, I find out that the .cctors may be called multi-times but only the first invocation will affect the setting of static fields. That's weird, but a good weirdness!
class MyClass
{
static int _val = 0;
static MyClass()
{
_val++;
Console.WriteLine (_val);
}
}
public static void Main (string[] args)
{
ConstructorInfo ci = typeof(MyClass).TypeInitializer;
ci.Invoke(new object[0]);
ci.Invoke(new object[0]);
ci.Invoke(new object[0]);
}
//result:
//1
//1
//1
//1
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我强烈建议您重新考虑您的设计。尝试使用这种“静态继承”解决方法正在与 .NET 的一些核心设计作斗争。
目前还不清楚您要解决的更大问题是什么,但是尝试像这样的“聪明”代码来模拟继承将导致代码从长远来看很难维护和诊断。
如果没有实际上使用
Deriv
的成员(或创建它的实例),您基本上不会触发静态构造函数。重要的是要了解Deriv.ShowValue()
基本上会转换为对 ... 的调用,因此您实际上并没有在
Deriv
上调用任何内容>。如果这样编写,您的调用代码实际上会更清晰。编辑:避免显式使用类型初始值设定项的另一个(显然不幸的)原因是 .NET 4.5 中存在一个错误,该错误会导致在某些情况下不适当地引发异常。有关详细信息,请参阅我关于该主题的问题。
I would strongly advise you to rethink your design. Attempting to use this sort of workaround for "static inheritance" is fighting against some of the core designs of .NET.
It's unclear what bigger problem you're trying to solve, but trying "clever" code like this to simulate inheritance will lead to code which is very hard to maintain and diagnose in the longer term.
Without actually using a member of
Deriv
(or creating an instance of it), you basically won't trigger the static constructor. It's important to understand thatDeriv.ShowValue()
is basically converted into a call to... so you're not actually calling anything on
Deriv
. Your calling code would actually be clearer if it were written that way.EDIT: One other (clearly unfortunate) reason to avoid using type initializers explicitly is that there's a bug in .NET 4.5 which causes an exception to be thrown inappropriately in some cases. See my question on the topic for more information.
正确的解决方案是像这样调用类型初始值设定项(= 静态构造函数):
它需要两个
null
。仅指定一个会引发MemberAccessException
。因此,您的代码可能看起来像这样:
这样,您就可以删除
new()
约束。The correct solution is to invoke the type initializer (= static constructor) like this:
It needs both
null
s. Specifying only one gives aMemberAccessException
.Thus, your code might want to look something like this:
And with that, you can remove the
new()
constraint.您无法控制静态构造函数何时执行,但可以保证它将在访问任何静态属性或方法之前以及实例化之前运行。
实际上没有理由希望静态构造函数提前执行。如果您没有使用类中的任何内容,但希望运行静态构造函数中的代码,那么您的设计就有问题。
You have no control of when the static constuctor will execute, but what is guaranteed is that it will run before accessing any static property or method and before instantiation.
There is really no reason to want the static constructor to execute at an earlier point. If you are not using anything from the class but you want the code in the static constructor to run, then something is wrong in your design.
静态构造函数是自动的,仅一次。你不能自己打电话给他们。
此处的示例:
输出:
Static constructors are automatically, only once. You cannot call them yourself.
An example from here:
output:
我引导您阅读有关 静态构造函数< 的 MSDN 文章/a> 以及页面下方大约 10% 的位置:
I direct you to the MSDN article on Static Constructors and about 10% down the page: