FieldInfo.GetValue() returns null 对于嵌套静态 class public 静态字段

FieldInfo.GetValue() returns null for a nested static class public static fields

我试图通过这个简单的代码获取嵌套静态 class 中的字段值:

public static class DataConstants {

    public static class Roles {

        public static readonly Role[] All = new Lazy<Role[]>(LoadAllRoles).Value;

        private static Role[] LoadAllRoles() {
            var fields = typeof(DataConstants.Roles)
                         .GetFields(BindingFlags.Public | BindingFlags.Static);

            foreach (var field in fields) {
                var r = field.GetValue(null);
            }
            return blah-blah;
        }

        public static readonly Role Role1 = new Role {
            Id        = -1,
            Name      = "role1",
        };

        public static Role Role2 = new Role {
            Id        = -2,
            Name      = "role2",
        };

    }

}

一切似乎都很好,我认为这应该可行。但是调用 field.GetValue(null) 总是 returns null。你知道我在这里错过了什么吗?提前致谢。

欢迎来到静态初始化的奇妙世界。静态成员按照声明的顺序初始化,AllRole1Role2 之前声明。因此 Role1Role2 直到 All 被分配后才被分配。

请注意,您在这里使用 Lazy<T> 是没有意义的:您立即调用 .Value,这意味着 LoadAllRolesAll 的初始化期间被调用。如果 All 实际上是一个 Lazy<T>(或者是一个包裹了 Lazy<T> 的 属性),而 Lazy<T>.Value 只是 Role1Role2 初始化后调用,你不会看到这个问题。

您可以将 Role1Role2 的声明移动到类型的顶部,All 上方,"fixes" 问题所在。不过,您最好在静态构造函数中分配 All,因为这不太容易发生意外损坏:

public static class DataConstants {

    public static class Roles {
        public static readonly Role[] All;

        static Roles()
        {
            All = LoadAllRoles();   
        }

        private static Role[] LoadAllRoles() {
            var fields = typeof(DataConstants.Roles)
                         .GetFields(BindingFlags.Public | BindingFlags.Static);

            foreach (var field in fields) {
                var r = field.GetValue(null);
                Console.WriteLine("field: " + r);
            }

            return new Role[0];
        }

        public static readonly Role Role1 = new Role {
            Id        = -1,
            Name      = "role1",
        };

        public static Role Role2 = new Role {
            Id        = -2,
            Name      = "role2",
        };
    }
}