Почему не статический конструктор, вызываемый в классе, используемом в качестве типичного параметра типа?

Учитывая следующие классы:

public class Foo {
    static Foo() {
        Console.WriteLine("Foo is being constructed");
    }
}

public class Bar {
    public void ReferenceFooAsGenericTypeParameter<T>() {
        Console.WriteLine("Foo is being referenced as a generic type parameter");
    }
}

public class SampleClass
{
    public static void Main()
    {
        new Bar().ReferenceFooAsGenericTypeParameter<Foo>();
    }
}

Выходной сигнал

Foo is being referenced as a generic type parameter

Это имеет смысл, согласно спецификации:

Статический конструктор вызывается автоматически для инициализации класса до создания первого экземпляра или ссылки на любые статические члены.

Но мне любопытно, почему статический конструктор не вызывается, когда тип ссылается как общий тип типа.

Ответ 1

Зачем это нужно?

Точкой статического конструктора, вызываемой обычно, является проверка того, что любое состояние, установленное внутри статического конструктора, инициализируется до его первого использования.

Просто использование Foo в качестве аргумента типа не использует какое-либо состояние внутри него, поэтому нет необходимости в вызове статического конструктора.

Возможно, вы захотите попробовать создать статический переменный инициализатор с побочными эффектами (например, вызов метода, который затем выводится на консоль) и удаление статического конструктора - в некоторых случаях может существенно повлиять на время инициализации. Это может вызвать это здесь.

Ответ 2

Это потому, что вы не можете фактически использовать содержимое типа каким-либо значимым образом, просто включив его в качестве параметра типового типа, тип должен сделать что-то для него, чтобы гарантировать, что вызываемый статический конструктор будет вызван.

И вы правы, что это соответствует спецификации. Раздел 10.12 (Статические конструкторы) гласит:

Выполнение статического конструктора инициируется первым из следующих событий, которые происходят в пределах домен приложения:

. Создается экземпляр типа класса.

. Ссылка на любой из статических членов типа класса.

Использовать в качестве параметра общего типа не является ни одним из них.

Ответ 3

Следует отметить, что в new Bar().ReferenceFooAsGenericTypeParameter<Foo>(); вы создали объект типа Bar, ни ваш основной, ни Bar не создали экземпляр Foo, и ни один из его членов не был доступ, в представленном случае, сам тип просто передается как параметр.