静态构造函数被调用多次

5
using System;

namespace ConsoleApplication15
{
  using System.Collections.Generic;
  using System.Threading;

  public static class Program
  {
    static void Main(string[] args)
    {
      var test1 = new Test<List<int>>();
      var t = new Thread(Tester);
      t.Start();

      var test2 = new Test<List<int>>();
      var test3 = new Test<List<int>>();
      var test4 = new Test<List<int>>();
      var test5 = new Test<List<int>>();


      test1.Do();
      test2.Do();
      test3.Do();
      test4.Do();
      test5.Do();
    }

    private static void Tester()
    {
      var test5 = new Test<IList<int>>();
      test5.Do();
    }
  }

  public class Test<T> where T : IEnumerable<int>
  {

    private static Something something;

    static Test()
    {
      Console.WriteLine("IM  static created ");

      something = new Something();
      Console.WriteLine(something.ToString());
    }

    public Test()
    {
      Console.WriteLine("IM  created ");
    }

    public void Do()
    {
      Console.WriteLine("Do something! ");
    }
  }

  public class Something
  {
    public Something()
    {
      Console.WriteLine("Create something");
    }
  }
}

当我运行上述代码时,我期望在 static Test() 中的静态构造函数只会被调用一次,但是当我运行代码时,静态构造函数被调用了两次!!!
当我删除这行代码 <T> where T : IEnumerable<int> 后,一切正常(静态构造函数只被调用一次)?!!
第一次调用的断点如下所示:This is the breakpoint for the first call,第二次调用的断点如下所示:This is the breakpoint for the second call

11
静态类型是针对每种类型而言的,而通用类型则是针对你指定的每个不同的“T”而言的类型。基本上,每个封闭式泛型都是一个类型本身,无论是从“Test<T>”定义的还是其他方式定义的。 - Adam Houldsworth
1
Test<List<int>> 不等于 Test<IList<int>> - Sorax
1
@AdamHouldsworth 你应该把那个发表为一个答案。 - Servy
post it please as answer! - Bassam Alugili
完成了,但是我的手机键盘没有在线代码格式的字符... - Adam Houldsworth
2个回答

7
静态成员是按类型进行的,而泛型类型为您指定的每个不同的 T 创建一个新类型。
基本上,每个封闭的泛型都是一个独立的类型,无论是从泛型模板定义的还是其他方式。
这是静态成员常见的陷阱。

我需要在静态构造器中进行一些工作(此工作将被称为一次应用程序域),但正如你所描述的,在这种情况下,构造器可能会被调用X次。我应该使用单例模式还是您有其他想法? - Bassam Alugili
@BassamAlugili 单例模式通常会使用静态方法(或者很可能会使用)。我可能会将其移动到一个静态类中,该类的唯一目的是包含此静态成员,并继续进行其他操作。 - Adam Houldsworth

2
在C#中,泛型类型的特定参数化实际上是唯一的类型。这是保留泛型类型信息作为运行时的优势,与像Java这样在编译过程中删除泛型类型信息的语言不同。
有许多用例可以使用泛型类型中的静态构造函数,例如以下内容: https://dev59.com/OGUo5IYBdhLWcg3w3ymi#15706192 另一个依赖于泛型类型中的静态构造函数每个封闭泛型类型运行一次的情况是类似于EqualityComparer<T>的类,其中静态构造函数可用于为每个类型T初始化Default属性。

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