显式调用静态构造函数

42

我希望为下面这个类编写单元测试。
如果名称不是"MyEntity",那么mgr应该为空。
负面单元测试
使用Manager私有访问器,我想将名称更改为"Test",以便mgr应该为null。 然后将验证mgr的值。 为了实现这一点,我想显式调用静态构造函数,但是当我使用

调用静态构造函数时,会发生错误。
Manager_Accessor.name = "Test"
typeof(Manager).TypeInitializer.Invoke(null, null); 

name 属性总是设置为 "MyEntity",如何将其设置为 "Test" 并调用静态构造函数。

public class Manager
{        
        private static string name= "MyEntity";

        private static object mgr;

        static Manager()
        {
            try
            {
                mgr = CreateMgr(name);
            }
            catch (Exception ex)
            {
                mgr=null;
            }
        }
}

2
将'mgr'定义为静态意味着所有'Manager'实例共享相同的'mgr'值,并且该值永远不能被更改(因为它是只读的)。这真的是你想要的吗? - Hans Kesting
4
所以你需要更改一个私有的硬编码静态值,该值负责设置私有的静态只读值,以进行测试?这就是为什么大多数针对可测试性的设计选择不喜欢静态元素。 - Adam Houldsworth
可能是如何运行静态构造函数?的重复问题。 - Wai Ha Lee
4个回答

53

今天我发现,静态构造函数是可以直接调用的:

来自另一个Stackoverflow帖子

其他答案都很好,但如果你需要在没有对类型的引用(即反射)的情况下强制运行类构造函数,可以使用以下方法:

Type type = ...;
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);  

我不得不在我的应用程序中添加这段代码以解决可能存在的 .net 4.0 CLR 缺陷


11

对于那些找到这个线程并想知道的人......我刚刚进行了测试。看起来只有当静态构造函数没有因其他原因而运行时,System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor()才会运行它。

例如,如果您的代码无法确定先前的代码是否访问了该类并触发了静态构造函数的运行,则无所谓。那个先前的访问将触发静态构造函数的运行,但然后RunClassConstructor()也不会运行它。 RunClassConstructor()仅在尚未运行静态构造函数时才运行它。

在RunClassConstructor()之后访问该类也不会导致静态构造函数再次运行。

这是基于在Win10 UWP应用程序中的测试结果。


这让我感到非常难过,因为现在每当我想要重置我的静态类的值时,我需要调用它的静态方法,该方法执行与构造函数完全相同的操作 - 设置默认值。 - user8620003
正确。你没有再次“构造”对象,只是设置它们的值。假设你已经构造了一个非静态对象,并在代码的许多不同位置存储了对它的引用。现在你想重置对象的值。你不会再次构造(“new”)对象。所有那些旧的存储引用仍然指向旧对象。相反,你将拥有一个方法,在已经构造的对象上重置值。然后你会发现构造函数和重置方法在做同样的事情,于是你只需从构造函数调用重置方法。 - kburgoyne
1
如果您需要重复运行,请参阅此处的答案:https://dev59.com/kXE85IYBdhLWcg3wr1ux#51758748。 - Brondahl

5

只需将public static void Initialize() { }方法添加到静态类中,并在需要时调用它。这与调用构造函数非常相似,因为静态构造函数将自动调用。


1
我认为这是正确的答案。它不依赖于未指定(至少我找不到)的RunClassConstructor行为,它只会执行静态构造函数一次。在类上调用空的“Initialize()”具有C#语言定义中指定的行为,可以依赖它。 - entiat

3

如果你的类中有静态成员(否则静态构造函数就没有太多用处),那么不需要显式调用静态构造函数。

只需访问你想调用其静态构造函数的类即可。例如:

public void MainMethod()
{
    // Here you would like to call the static constructor

    // The first access to the class forces the static constructor to be called.
    object temp1 = MyStaticClass.AnyField;

    // or
    object temp2 = MyClass.AnyStaticField;
}

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