Question

No problems getting at the type

I am easily able to get at a nested property which is private by nature.

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);

The problem is that my _entityConfigurations is a type of:

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

Note that the second type is internal and will not compile if I add it to the code. I have tried to cast to dynamic and object but both give me errors that say the protection level is not allowed.

I need a way to iterate the returned dicationary somehow.

Était-ce utile?

La solution 2

Found a solution!

The dictionary key was type. There was another property that listed the types and was easily casted to IEnumerable since System.Type is public. Then in a foreach loop I was able to iterate the types. At the same time I could then call the internal "get_item" function of the dictionary passing the type as a parameter.

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

As Jon said below, this is very brittle because I am relying on internal implementation details subject to possible change in the future. This is not a good solution. Unfortunately, I haven't found a way to get the information I need in a more elegant way so far. Maybe, I could let Microsoft know that I need this meta information exposed in a more public way for the internal EntityTypeConfiguration type. But, until they listen I am left with few options.

This is a needed for a design-time tool to used for the collection of schema information set by the Code-First EntityFramework Fluent API. Prior to this I implemented a suite of wrapper classes that replace the EntityTypeConfiguration which followed a Wrapper-Delegation pattern where I could squirrel away the metadata I needed. There is more responsibility on both the myself and the user when using this pattern (ie. for Map Classes the user is forced to inherit from my custom implementation EntityTypeMetaConfiguration and for database context classes my [DbMetaContext : DbContext] is needed, not to mention the need for using a different overide for OnModelCreating).

Autres conseils

Internal types are types which aren't exposed outside the assembly, and private nested types are even more restricted.

As you stated that you've tried dynamic and object and got errors, here I'm using a example to represent your problem and for demonstration of how can you do that. I used a nested private class System.Array.ArrayEnumerator which comes with the framework instead.

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>();
}

As I mentioned before, private nested types are more restricted. My code is not allowed to use Array.ArrayEnumerator, and I got no information of it at compile time, thus object is chosen. dynamic would not be helpful here, and will throw at runtime if I attempted to access the members of an ArrayEnumerator.

As you can see if you tested the code, it runs with no problem. The annoying thing is that you will need to do everything via reflection with the values of the dictionary.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top