返回Dictionary <type,internaltype>和iterate </type,internaltype>的私有属性的GetField

时间:2013-06-30 07:17:47

标签: c# entity-framework ef-code-first system.reflection

没有问题

我很容易得到一个私有的嵌套属性。

var modelConfigurationFieldInfo=
        _modelBuilder.Configurations.GetType().GetField(
            "_modelConfiguration",
            System.Reflection.BindingFlags.NonPublic
            |System.Reflection.BindingFlags.Instance
            );

var modelConfiguration=
        modelConfigurationFieldInfo.GetValue(
            _modelBuilder.Configurations);

var entityConfigurationsFieldInfo=
        modelConfiguration.GetType().GetField(
            "_entityConfigurations",
            System.Reflection.BindingFlags.NonPublic
            |System.Reflection.BindingFlags.Instance
            );

var entityConfigurations=
        entityConfigurationsFieldInfo.GetValue(modelConfiguration);

问题是my _entityConfigurations是一种类型:

  

Dictionary`Type,System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration

请注意,第二种类型是内部的,如果我将其添加到代码中则不会编译。我试图转发dynamicobject,但两者都给我错误,说不允许保护等级

我需要一种方法以某种方式迭代返回的dicationary。

2 个答案:

答案 0 :(得分:1)

Internal types是未在程序集外公开的类型,而私有nested types则更受限制。

正如您所说,您已尝试dynamicobject并遇到错误,此处我将使用一个示例来表示您的问题并演示如何执行此操作。我使用了一个嵌套的私有类System.Array.ArrayEnumerator来代替框架。

public static partial class TestClass {
    public static void TestMethod() {
        var internalType=
                typeof(Array).GetNestedType(
                    "ArrayEnumerator", BindingFlags.NonPublic);

        var x=new SampleClass();
        var type=x.GetType();
        var bindingAttr=BindingFlags.Instance|BindingFlags.NonPublic;
        var info=type.GetField("dict", bindingAttr);
        var dict=info.GetValue(x) as IDictionary<Type, object>;
        var arrayEnumerator=dict[internalType];
    }
}

partial class SampleClass {
    public SampleClass() {
        var internalType=
                typeof(Array).GetNestedType(
                    "ArrayEnumerator", BindingFlags.NonPublic);

        var invokeAttr=
                BindingFlags.CreateInstance|
                BindingFlags.Instance|
                BindingFlags.NonPublic;

        var array=new[] { 1, 2, 3 } as IList;
        var args=new object[] { array, 0, array.Count };

        var arrayEnumerator=
                internalType.InvokeMember(
                    ".ctor", invokeAttr, null, null, args);

        dict.Add(internalType, arrayEnumerator);
    }

    Dictionary<Type, object> dict=new Dictionary<Type, object>();
}

正如我之前提到的,私有嵌套类型受到更多限制。我的代码不允许使用Array.ArrayEnumerator,并且在编译时我没有得到它的信息,因此选择了objectdynamic在这里没有帮助,如果我试图访问ArrayEnumerator的成员,它将在运行时抛出。

正如您所看到的,如果您测试了代码,它运行没有问题。令人讨厌的是,你需要通过反映字典的值来做所有事情。

答案 1 :(得分:1)

找到解决方案!

字典键是类型。还有另一个属性列出了类型,并且很容易转换为 IEnumerable ,因为 System.Type 是公共的。然后在foreach循环中,我能够迭代类型。然后,我可以调用字典的内部“get_item”函数,将类型作为参数传递。

foreach(var type in types) 
{ 
    var data = entityConfigurations.GetType().GetMethod("get_Item")
                    .Invoke(new object[] { type });
    // Get more information here.
}

正如乔恩在下面所说,这非常脆弱,因为我依赖内部实施细节,可能会在未来发生变化。这不是一个好的解决方案。不幸的是,到目前为止,我还没有找到一种以更优雅的方式获取所需信息的方法。也许,我可以让微软知道我需要以更公开的方式为内部 EntityTypeConfiguration 类型公开这个元信息。但是,直到他们听,我才剩下几个选择。

这是设计时工具所需,用于收集Code-First EntityFramework Fluent API设置的架构信息。在此之前,我实现了一套包装类,它们取代了 EntityTypeConfiguration ,它遵循Wrapper-Delegation模式,我可以将我需要的元数据放在一边。使用此模式时,我自己和用户都有更多的责任(即,对于Map Classes,用户必须从我的自定义实现EntityTypeMetaConfiguration继承,对于数据库上下文类,我的[ DbMetaContext :DbContext]是必要的,更不用说为 OnModelCreating 使用不同的覆盖。