[英]Why is FieldInfo.GetValue(null) not working in static constructor
See the code below. 请参见下面的代码。 I want a class that automatically enumerates all the defined static readonly instances of its own type (see TestClass as an example, it defines 3 static readonly instances of its own type).
我想要一个能够自动枚举其自身类型的所有已定义静态只读实例的类(例如,请参见TestClass,它定义了其自身类型的3个静态只读实例)。
I want this automation because I want to loop over the defined types and not risk the change of forgetting to add a new instance to the list of All
. 我想要这种自动化,因为我想遍历定义的类型,而不必冒险忘记将新实例添加到
All
列表中而进行更改。
Ok, I have it working, that is not the point. 好吧,我已经开始工作了,那不是重点。 But why doesn't
FillAll
work when called from a static constructor? 但是为什么从静态构造函数调用
FillAll
不起作用? See the commented static constructor in DefinedInstancesBase<T>
code. 请参见
DefinedInstancesBase<T>
代码中DefinedInstancesBase<T>
注释的静态构造函数。 I mean FieldInfo.GetValue(null)
returns null in the static constructor, though the debugger has already hit creating the static readonly instances before the FieldInfo.GetValue(null)
is called. 我的意思是,尽管调试器已经在调用
FieldInfo.GetValue(null)
之前创建了静态只读实例,但FieldInfo.GetValue(null)
在静态构造函数中返回null。
I'm very curious why it doesn't work. 我很好奇为什么它不起作用。 Is this by design?
这是设计使然吗?
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;
}
}
}
There are two separate issues at work here. 这里有两个单独的问题在起作用。
static
constructor in the code above. static
构造函数中有一个错字。 Try changing static DefinedInstances()
to static DefinedInstancesBase()
, because currently it is just specified as a private static function. static DefinedInstances()
更改为static DefinedInstancesBase()
,因为当前它只是被指定为私有静态函数。 First
field in the derived class. First
字段的实例化触发的。派生类。 Therefore, First
is still null when the static
constructor of DefinedInstancesBase
class is being called (and thus the FindAll()
method). DefinedInstancesBase
类的static
构造函数(并因此调用FindAll()
方法)时, First
仍然为null。 See the following code (slightly modified to better illustrate the issue) and output: 请参见以下代码(稍作修改以更好地说明问题)并输出:
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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.