通用 类 中特定于类型的静态状态
Type-specific static state in generic classes
考虑这段代码:
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 方法呈现给它的每种类型新建总线 class。为此,它必须为每个新类型调用 Bus<T>
上的默认构造函数。
但是为什么呢?这是如何工作的?
这是否有任何实际用途,或者它只是 C# 的一个有趣但晦涩的好奇心,应该在生产代码中避免?
是的,传递给静态 class Bus<T>
的每个不同类型都会导致调用默认构造函数。验证这一点的一个简单方法是给它一个默认构造函数:
static Bus(){ Debug.Print("ctor"); }
使用它会产生输出
ctor
ctor
3
1
原因是通用 classes 只是 classes 的模板,静态 classes 仍然如此。一旦为 Bus
class 指定了泛型类型,模板就会具体化为 class,这就是调用构造函数的时间。
这个具体化的 class 对于相同 class 的其他泛型类型是唯一的。因此,当使用 Bus<Person>
和 Bus<Animal>
时,它们实际上是单独的 classes,具有单独的静态成员数据,并且需要单独的实例化。
关于具有通用类型的静态字段的使用和前景,有一个 MSDN 警告(显然 Resharper 会注意到它)
CA1000: Do not declare static members on generic types
https://msdn.microsoft.com/en-us/library/ms182139(VS.80).aspx
考虑这段代码:
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 方法呈现给它的每种类型新建总线 class。为此,它必须为每个新类型调用 Bus<T>
上的默认构造函数。
但是为什么呢?这是如何工作的?
这是否有任何实际用途,或者它只是 C# 的一个有趣但晦涩的好奇心,应该在生产代码中避免?
是的,传递给静态 class Bus<T>
的每个不同类型都会导致调用默认构造函数。验证这一点的一个简单方法是给它一个默认构造函数:
static Bus(){ Debug.Print("ctor"); }
使用它会产生输出
ctor
ctor
3
1
原因是通用 classes 只是 classes 的模板,静态 classes 仍然如此。一旦为 Bus
class 指定了泛型类型,模板就会具体化为 class,这就是调用构造函数的时间。
这个具体化的 class 对于相同 class 的其他泛型类型是唯一的。因此,当使用 Bus<Person>
和 Bus<Animal>
时,它们实际上是单独的 classes,具有单独的静态成员数据,并且需要单独的实例化。
关于具有通用类型的静态字段的使用和前景,有一个 MSDN 警告(显然 Resharper 会注意到它)
CA1000: Do not declare static members on generic types
https://msdn.microsoft.com/en-us/library/ms182139(VS.80).aspx