【问题标题】:Type-specific static state in generic classes泛型类中特定于类型的静态状态
【发布时间】:2026-01-04 18:25:02
【问题描述】:

考虑这段代码:

public class Person
{
    public string Name { get; set; }
}

public class Animal
{ 
    public string Name { get; set; }
}

public interface IHandler<T>
{
    T Handle(T eventData);
}

public class UpdatePersonHandler : IHandler<Person>
{
    public Person Handle(Person eventData)
    {
        var test = eventData.Name;
        return eventData;
    }
}
public class UpdatePersonHandler2 : IHandler<Person>
{
    public Person Handle(Person eventData)
    {
        var test = eventData.Name;
        return eventData;
    }
}
public class UpdateAnimalHandler : IHandler<Animal>
{
    public Animal Handle(Animal eventData)
    {
        var test = eventData.Name;
        return eventData;
    }
}

public class Bus<T>
{
    public static readonly IList<IHandler<T>> Handlers = new List<IHandler<T>>();

    public static void Register(IHandler<T> handler)
    {
        if (handler != null)
            Handlers.Add(handler);
    }

    public static void Raise(T eventData)
    {
        foreach (var handler in Handlers)
        {
            handler.Handle(eventData);
        }
    }
}

还有这个测试代码:

[TestMethod]
public void TestRegister()
{
    Bus<Person>.Register(new UpdatePersonHandler());
    Bus<Person>.Register(new UpdatePersonHandler());
    Bus<Person>.Register(new UpdatePersonHandler2());

    Bus<Animal>.Register(new UpdateAnimalHandler());

    Debug.Print(Bus<Person>.Handlers.Count.ToString());
    Debug.Print(Bus<Animal>.Handlers.Count.ToString());
}

这个测试的输出是:

3
1

这里发生了什么?

看起来框架正在为通过static Register 方法呈现给它的每种类型新建一个总线类。为此,它必须为每个新类型调用Bus&lt;T&gt; 上的默认构造函数。

但是为什么呢?这是如何工作的?

这是否有任何实际用途,或者仅仅是在生产代码中应该避免的对 C# 的有趣但晦涩的好奇心?

【问题讨论】:

标签: c# generics static static-methods


【解决方案1】:

是的,传递给静态类Bus&lt;T&gt; 的每种不同类型都会导致调用默认构造函数。验证这一点的一种简单方法是给它一个默认构造函数:

static Bus(){ Debug.Print("ctor"); }

使用它产生输出

ctor
ctor
3
1

原因是泛型类只是类的模板,静态类仍然如此。一旦为Bus 类提供了一个泛型类型,那么模板就会被具体化为一个类,这就是调用构造函数的时候。

这个物化类是同一类的其他泛型类型所独有的。因此,当使用Bus&lt;Person&gt;Bus&lt;Animal&gt; 时,它们实际上是单独的类,具有单独的静态成员数据,并且需要单独的实例化。

关于具有通用类型的静态字段的使用和前景,有一个 MSDN 警告(显然 Resharper 会选择这个)

CA1000:不要在泛型类型上声明静态成员
https://msdn.microsoft.com/en-us/library/ms182139(VS.80).aspx

【讨论】:

  • 微软似乎暗示这种做法的问题在于它会干扰类型推断。类的多个实例化(每种类型一个)似乎根本不会打扰他们。可以说是“按设计”。
  • @RobertHarvey:“类的多个实例化(每种类型一个)似乎根本不会打扰他们”——确切地说,也不应该。甚至类型推断的问题也值得商榷。如果归根结底,您需要的是一个静态泛型类,或者一个没有任何泛型类型参数的泛型方法,那么这就是您需要做的。它确实发生了(一个例子是处理enum 类型的辅助方法)。请注意,扩展方法减轻了一些此类场景的痛苦。
  • 很好,我现在明白了
最近更新 更多