C# 为什么FieldInfo.GetValue(null)不能在静态构造函数中工作
请参阅下面的代码。我想要一个类,它自动枚举它自己类型的所有已定义的静态只读实例(例如,请参见TestClass,它定义了它自己类型的3个静态只读实例) 我希望实现这种自动化,因为我希望在定义的类型上循环,而不冒忘记将新实例添加到C# 为什么FieldInfo.GetValue(null)不能在静态构造函数中工作,c#,reflection,static-constructor,C#,Reflection,Static Constructor,请参阅下面的代码。我想要一个类,它自动枚举它自己类型的所有已定义的静态只读实例(例如,请参见TestClass,它定义了它自己类型的3个静态只读实例) 我希望实现这种自动化,因为我希望在定义的类型上循环,而不冒忘记将新实例添加到All列表的风险 好的,我让它工作了,这不是重点。但是为什么从静态构造函数调用时,FillAll不起作用呢?请参阅definedInstanceBasecode中注释的静态构造函数。我的意思是FieldInfo.GetValue(null)在静态构造函数中返回null,尽
All
列表的风险
好的,我让它工作了,这不是重点。但是为什么从静态构造函数调用时,FillAll
不起作用呢?请参阅definedInstanceBase
code中注释的静态构造函数。我的意思是FieldInfo.GetValue(null)
在静态构造函数中返回null,尽管调试器在调用FieldInfo.GetValue(null)
之前已经创建了静态只读实例
我很好奇为什么它不起作用。这是故意的吗
public abstract class DefinedInstancesBase<T>
{
public static IList<T> All
{
get
{
if (_All == null)
{
FillAll();
}
return _All;
}
}
//Why this doesn't work? No idea.
//static DefinedInstancesBase()
//{
// FillAll();
//}
private static void FillAll()
{
var typeOfT = typeof(T);
var fields = typeOfT.GetFields(BindingFlags.Public | BindingFlags.Static);
var fieldsOfTypeT = fields.Where(f => f.FieldType == typeOfT);
_All = new List<T>();
foreach (var fieldOfTypeT in fieldsOfTypeT)
{
_All.Add((T)fieldOfTypeT.GetValue(null));
}
}
private static List<T> _All = null;
}
[TestClass]
public class DefinedInstancesTest
{
[TestMethod]
public void StaticReadOnlyInstancesAreEnumerated()
{
//Given
var expectedClasses = new List<TestClass>
{
TestClass.First,
TestClass.Second,
TestClass.Third,
};
//When
var actualClasses = TestClass.All;
//Then
for (var i=0; i<expectedClasses.Count; i++)
{
Assert.AreEqual(expectedClasses[i].Id, actualClasses[i].Id);
}
}
private class TestClass : DefinedInstancesBase<TestClass>
{
public static readonly TestClass First = new TestClass(1);
public static readonly TestClass Second = new TestClass(2);
public static readonly TestClass Third = new TestClass(3);
public int Id { get; private set; }
private TestClass(int pId)
{
Id = pId;
}
}
}
公共抽象类definedInstanceBase
{
公共静态IList All
{
得到
{
如果(_All==null)
{
FillAll();
}
全部归还;
}
}
//为什么这样不行?不知道。
//静态定义的stancesbase()
//{
//FillAll();
//}
私有静态void FillAll()
{
var typeOfT=typeof(T);
var fields=typeOfT.GetFields(BindingFlags.Public | BindingFlags.Static);
var fieldsOfTypeT=字段,其中(f=>f.FieldType==typeOfT);
_All=新列表();
foreach(变量fieldOfTypeT在FieldSoftTypet中)
{
_All.Add((T)fieldOfTypeT.GetValue(null));
}
}
私有静态列表_All=null;
}
[测试类]
公共类定义的状态测试
{
[测试方法]
public void StaticReadOnlyInstancesAreEnumerated()
{
//给定
var expectedClasses=新列表
{
TestClass。首先,
测试类。第二,
测试类。第三,
};
//什么时候
var actualClasses=TestClass.All;
//然后
对于(var i=0;i,这里有两个独立的问题
上面代码中的static
构造函数中存在键入错误。请尝试将static DefinedInstances()
更改为static definedInstancebase()
,因为当前它只是指定为私有静态函数
第二个也是更重要的问题是理解各种构造函数被调用的顺序。发生的是,基本抽象类上的静态构造函数被实例化触发(在成员初始化过程中)派生类中的First
字段。因此,当调用definedInstanceBase
类的static
构造函数(以及FindAll()
方法)时,First
仍然为空
请参阅以下代码(稍作修改以更好地说明问题)和输出:
public void Main()
{
DefinedInstancesTest dit = new DefinedInstancesTest();
dit.StaticReadOnlyInstancesAreEnumerated();
}
public abstract class DefinedInstancesBase<T>
{
public static IList<T> All
{
get
{
//if (_All == null)
// FillAll();
return _All;
}
}
// correctly named static ctor
static DefinedInstancesBase() { FillAll(); }
private static void FillAll()
{
Console.WriteLine("FillAll() called...");
var typeOfT = typeof(T);
var fields = typeOfT.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
var fieldsOfTypeT = fields.Where(f => f.FieldType == typeOfT);
_All = new List<T>();
foreach (var fieldOfTypeT in fieldsOfTypeT)
{
_All.Add((T)fieldOfTypeT.GetValue(null));
}
}
private static List<T> _All = null;
}
//[TestClass]
public class DefinedInstancesTest
{
//[TestMethod]
public void StaticReadOnlyInstancesAreEnumerated()
{
//Given
var expectedClasses = new List<TestClass>
{
TestClass.First,
TestClass.Second,
TestClass.Third,
};
//When
var actualClasses = TestClass.All;
//Then
for (var i=0; i<expectedClasses.Count; i++)
{
//Assert.AreEqual(expectedClasses[i].Id, actualClasses[i].Id);
if (expectedClasses[i].Id != actualClasses[i].Id)
Console.WriteLine("not equal!");
}
}
private class TestClass : DefinedInstancesBase<TestClass>
{
public static readonly TestClass First;
public static readonly TestClass Second;
public static readonly TestClass Third;
public int Id { get; private set; }
static TestClass()
{
Console.WriteLine("TestClass() static ctor called...");
First = new TestClass(1);
Second = new TestClass(2);
Third = new TestClass(3);
}
private TestClass(int pId)
{
Console.WriteLine("TestClass({0}) instance ctor called...", pId);
Id = pId;
}
}
}
TestClass() static ctor called...
// the line "First = new TestClass(1);" now triggers the base class static ctor to be called,
// but the fields First, Second, and Third are all still equal to null at this point!
FillAll() called...
TestClass(1) instance ctor called...
TestClass(2) instance ctor called...
TestClass(3) instance ctor called...
// this null reference exception to be expected because the field value actually was null when FindAll() added it to the list
Unhandled Expecption:
System.NullReferenceException: Object reference not set to an instance of an object.
public void Main()
{
DefinedInstanceTest dit=新定义的InstanceTest();
StaticReadOnlyInstancesAreEnumerated();
}
公共抽象类definedInstanceBase
{
公共静态IList All
{
得到
{
//如果(_All==null)
//FillAll();
全部归还;
}
}
//正确命名的静态构造函数
静态定义的StanceBase(){FillAll();}
私有静态void FillAll()
{
WriteLine(“FillAll()调用…”);
var typeOfT=typeof(T);
var fields=typeOfT.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
var fieldsOfTypeT=字段,其中(f=>f.FieldType==typeOfT);
_All=新列表();
foreach(变量fieldOfTypeT在FieldSoftTypet中)
{
_All.Add((T)fieldOfTypeT.GetValue(null));
}
}
私有静态列表_All=null;
}
//[测试类]
公共类定义的状态测试
{
//[测试方法]
public void StaticReadOnlyInstancesAreEnumerated()
{
//给定
var expectedClasses=新列表
{
TestClass。首先,
测试类。第二,
测试类。第三,
};
//什么时候
var actualClasses=TestClass.All;
//然后
for(var i=0;iI不遵循..它编译。并且typeof(T)
正在工作。你的意思是什么,你能详细说明一下吗?构造函数必须和它们的类同名,你的类不能。你的类叫做definedInstanceBase,但是(注释掉了)构造函数有一个不同的名称-它被称为DefinedInstances,也就是说,它实际上不是一个构造函数。哇,我的错。这是一个重命名,后来当静态构造函数已经成为一条注释时应用。所以这不是问题。所以本质上,试着通过调用FillAll()使TestMethod
工作
在静态构造函数中
不是延迟加载属性All
@mikedklerk,它本身不是延迟加载问题。它是在第一个
字段初始化为对象之前调用基类中的静态构造函数。因此该字段的当前值(在调用FindAll()
时)正确返回为null
。