简体   繁体   中英

BindingFlags.DeclaredOnly alternative to avoid ambiguous properties of derived classes (AmbiguousMatchException)

I'am looking for a solution to access 'flatten' (lowest) properties values of a class and its derived via reflection by property names.

ie access either Property1 or Property2 from the ClassB or ClassC type :

   public class ClassA
    {
        public virtual object Property1 { get; set; }

        public object Property2 { get; set; }
    }
    public class ClassB : ClassA
    {
        public override object Property1 { get; set; }
    }
    public class ClassC : ClassB
    {
    }

Using simple reflection works until you have virtual properties that are overrired (ie Property1 from ClassB ). Then you get a AmbiguousMatchException because the searcher don't know if you want the property of the main class or the derived.

Using BindingFlags.DeclaredOnly avoid the AmbiguousMatchException but unoverrided virtual properties or derived classes properties are ommited (ie Property2 from ClassB ).

Is there an alternative to this poor workaround :

// Get the main class property with the specified propertyName
PropertyInfo propertyInfo = _type.GetProperty(propertyName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

    // If not found, get the property wherever it is
    if (propertyInfo == null)
            propertyInfo = _type.GetProperty(propertyName);

Furthermore, this workaround not resolve the reflection of 2nd level properties : getting Property1 from ClassC and AmbiguousMatchException is back.

My thoughts : I have no choice except loop... Erk... ??

I'am open to Emit, Lambda (is the Expression.Call can handle this?) even DLR solution.

Thanks !

The only way to do this is to enumerate all of the properties and filter out the duplicates.

I'd recommend using a library like Fasterflect to do this. It solves the hard problems and gives you a ton of nice features over what you can do with standard reflection.

// find properties and remove duplicates higher up the hierarchy
var properties = type.Properties( Flags.ExcludeBackingMembers );

Solution with Fasterflect :

foreach (PropertyInfo propertyInfo in objType.Properties(Flags.ExcludeBackingMembers | Flags.Public | Flags.Static | Flags.Instance))
{
    FasterflectPropertyValue(propertyInfo.Name, obj);
}

private static object FasterflectPropertyValue(string propertyName, object obj)
{
    return obj.GetPropertyValue(propertyName);
}

Reflection from Class1 - 1 loops :3602674ticks
Reflection from Class2 - 1 loops :2940541ticks
Reflection from Class3 - 1 loops :1035300ticks
Reflection from Class1 - 100 loops :2ms
Reflection from Class2 - 100 loops :2ms
Reflection from Class3 - 100 loops :3ms
Reflection from Class1 - 10000 loops :274ms
Reflection from Class2 - 10000 loops :284ms
Reflection from Class3 - 10000 loops :295ms
Fasterflect from Class1 - 1 loops :44ms
Fasterflect from Class2 - 1 loops :2508656ticks
Fasterflect from Class3 - 1 loops :2314142ticks
Fasterflect from Class1 - 100 loops :3223064ticks
Fasterflect from Class2 - 100 loops :5056514ticks
Fasterflect from Class3 - 100 loops :5166725ticks
Fasterflect from Class1 - 10000 loops :96ms
Fasterflect from Class2 - 10000 loops :138ms
Fasterflect from Class3 - 10000 loops :162ms

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM