泛型类型的静态构造函数是如何工作的?

7
public abstract class EventSystemBase<T, K> : IAutoEvent
    where T : Event
    where K : IAutoEvent, new()
{
    public static T Instance { get { return EventSystem.Events.OfType<T>().FirstOrDefault(); } }
    public static IAutoEvent AutoEventInstance { get { return new K(); } }

    static EventSystemBase()
    {
        EventBot.Register(new EventBotEntry(Instance.Name, AutoEventInstance));
    }

    [...]
}

我不太理解这个是如何编译的。

  • 静态构造函数什么时候运行?
  • 为什么可以在静态成员中使用泛型类型?
  • 它应该如何知道要应用哪些类型?
4个回答

7
  • 静态构造函数在第一次需要时执行。确切的时间点有些棘手,因为如果二进制文件中有像beforefieldinit这样的标志,你可能不需要太担心细节,只需知道它会在访问第一个类成员之前运行。

  • 那么,为什么不呢?:) 每个形式为EventSystemBase<T, K>的类型都是独立的类,并且与类的其他泛型实例没有关系,因此构造函数需要为每个实例运行。对于运行时来说,它们在所有*方面都是不同的。

  • 静态构造函数针对“经过处理”的类型而不是“未经加工”的类型运行(即它针对已替换泛型类型的版本运行),因此这里没有真正的问题。

*实际上,运行时避免创建引用类型泛型的重复实例。但对于程序员或程序来说,这并不重要。


2
静态构造函数不适用于开放式泛型类型。它只在您指定类型参数时才会运行,例如,EventSystemBase<MyEvent, MyAutoEvent>,这实际上是与EventSystemBase<AnotherEvent, MyAutoEvent>不同的类,有其自己的静态构造函数。在每种情况下,在创建该单独类的第一个实例或引用其任何静态成员之前,静态构造函数都会运行。

实际上,从我测试的结果来看,基类Foo<T>中的静态成员被Foo<int>和Foo<string>共享。 - bevacqua
class Foo<T> {public static int x = 0;} Foo<int>.x = 10; Console.WriteLine(Foo<string>.x) //仍然是零 - Mark Cidade

1

如果基于我过去的c ++知识,它应该是一样的...

泛型在编译时生成,并转换为许多单独而不同的类。对于每个这些类,静态构造函数在任何代码引用静态类之前运行。 CLR 知道引用哪些类型,因为每个类都是独特的

EventSystemBase < 字符串字节>与EventSystemBase < 字符串整数>没有任何关系。就好像您在源代码中编写了两个完全分开的类一样。

class Program
{
    public static void Main()
    {
        var myInt = new MyGeneric<int>();
        myInt.InstanceMethod();
        MyGeneric<int>.StaticMethod();

        MyGeneric<long>.StaticMethod();
        var myLong = new MyGeneric<long>();
        myLong.InstanceMethod();

        Console.ReadLine();
    }
}

public class MyGeneric<T>
{
    static MyGeneric()
    {
        Console.WriteLine("Static constructor: {0}", typeof(T).Name);
    }

    public static void StaticMethod()
    {
        Console.WriteLine("Static method: {0}", typeof(T).Name);
    }

    public void InstanceMethod()
    {
        Console.WriteLine("Instance method: {0}", typeof(T).Name);
    }
}

4
泛型不是在编译时生成的! - user541686
尽管语法相似,但C#泛型与C++模板的工作方式不同。 - Mark Cidade
除了编译部分,这个是正确的吗?他们还去掉了我的防XSS的尖括号...否则我倒数第二句话会更有意义:( - cwharris
除此之外,它相当准确。 - Mark Cidade

0
  1. 每次调用不同的<T,K>泛型类时,都会调用该泛型的静态构造函数。

2-3. 根据1可以清楚地看出,它与T,K泛型有关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接