c# system - GetProperty reflection results in “Ambiguous match found” on new property



ambiguousmatchexception powershell (6)

How can I get my property? Currently an error is occuring of Ambiguous match found, see the comment line in code.

public class MyBaseEntity
{
    public MyBaseEntity MyEntity { get; set; }
}

public class MyDerivedEntity : MyBaseEntity
{
    public new MyDerivedEntity MyEntity { get; set; }
}

private static void Main(string[] args)
{
    MyDerivedEntity myDE = new MyDerivedEntity();

    PropertyInfo propInfoSrcObj = myDE.GetType().GetProperty("MyEntity");
    //-- ERROR: Ambiguous match found
}

Answers

Type.GetProperty

Situations in which AmbiguousMatchException occurs ...

...derived type declares a property that hides an inherited property with the same name, by using the new modifier

If you run the following

var properties = myDE.GetType().GetProperties().Where(p => p.Name == "MyEntity");

you will see that two PropertyInfo objects are returned. One for MyBaseEntity and one for MyDerivedEntity. That is why you are receiving the Ambiguous match found error.

You can get the PropertyInfo for MyDerivedEntity like this:

PropertyInfo propInfoSrcObj = myDE.GetType().GetProperties().Single(p => 
    p.Name == "MyEntity" && p.PropertyType == typeof(MyDerivedEntity));

The ambiguity occurs because of the new declaration in MyDerivedEntity. To overcome this you can use LINQ:

var type = myObject.GetType();
var colName = "MyEntity";
var all = type.GetProperties().Where(x => x.Name == colName);
var info = all.FirstOrDefault(x => x.DeclaringType == type) ?? all.First();

This will grab the property out of the derived type if it exists, otherwise the base. This can easily be flip-flopped if needed.


Kevin already pointed out the issue, but you don't need complex statements, or LINQ for that:

PropertyInfo propInfoSrcObj = myDE.GetType().
    GetProperty("MyEntity", typeof(MyDerivedEntity));

For property:

MemberInfo property = myDE.GetProperty(
    "MyEntity",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

For method:

MemberInfo method = typeof(String).GetMethod(
    "ToString",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly,
    null,
    new Type[] { },// Method ToString() without parameters
    null);

BindingFlags.DeclaredOnly - Specifies that only members declared at the level of the supplied type's hierarchy should be considered. Inherited members are not considered.


I was having this issue with MsgPack serialization of my LocationKey object. Ended up being the operators I had defined in my LocationKey class. Having both of these operators defined caused DefaultContext.GetSerializer(obj.GetType()); to throw Ambiguous Match Found when trying to serialize. Removing one set of operators made the issue go away.

public static bool operator ==(int key1, LocationKey key2)
{
    return key1 == key2.Value;
}

public static bool operator !=(int key1, LocationKey key2)
{
    return key1 != key2.Value;
}

public static bool operator ==(LocationKey key1, int key2)
{
    return key1.Value == key2;
}

public static bool operator !=(LocationKey key1, int key2)
{
    return key1.Value != key2;
}

Thanks to ken for the information. It looks like the best solution I can get it to filter them out by testing GetSetMethod(true) in a LINQ filter:

//Get all public or private non-static properties declared in this class (no inherited properties) - that have a getter and setter.
PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(p => p.GetGetMethod(true) != null && p.GetSetMethod(true) != null).ToArray();




c# reflection system.reflection