GetProperty reflection results in "Ambiguous match found" on new property
Asked Answered
D

8

43

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
}
Dead answered 12/7, 2012 at 0:59 Comment(2)
Runtime error or compile time error?Typewrite
@Dead Please reconsider the selected answer. Many will come here with conditional constructs like if (winform.GetType().GetProperty("Items") != null) {..} in which case one merely switches Exceptions using Linq...Doing
B
52

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));
Brahmin answered 12/7, 2012 at 1:8 Comment(5)
+1. Good hands on explanation. I've added RTFM link just in case.Prevalent
fantastic stuff! I simplified it to type.GetProperties().First(p => p.Name == "MyEntity") All tests are green!Dead
Regardless of First or Single, both will throw an exception when no elements are present to begin with!Doing
Not so good as next answer, cause you forced to use name of Type. It is not always possible.Irrespirable
I would match the DeclaringType rather than the PropertyType so you can specify which class you want to match the property for, as in some cases they might have the same type.Schmeltzer
M
39

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.

Melanism answered 26/2, 2014 at 19:30 Comment(1)
I can't understand why this isn't the most upvoted answer, it's the only safe solution since the first answer tries to match the return type instead of using that simple flag.Ichabod
T
24

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.

Tommi answered 2/11, 2015 at 16:11 Comment(4)
It is more universal and extensible solution really.Bucktooth
Very efficient solution! But I fear the order of the properties is not guaranteed: The M:System.Type.GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies. (Taken from MSDN Documentation)Briefcase
A better and more universal solution than the widely accepted answer at the topPizzicato
This is the best answer because you can decide whether or not to prefer the "new" property or that of the base class.Taste
D
11

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));
Doing answered 27/9, 2013 at 20:15 Comment(0)
H
1

I got this error in browser console I search for it and I found this exception is for c# and answer is also for c# then I try to look at my code and I found the where the problem occurs :

I have an ajax post method and when I post data got this error so the data I have passed will be collected by c# web method, so when I see that model I have 2 properties with the same name so I remove one and problem and exception got solved.

Hygrostat answered 10/3, 2018 at 10:45 Comment(0)
C
0

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;
}
Curia answered 3/4, 2015 at 20:18 Comment(0)
Y
0

For me, in VB.Net, I encountered this super descriptive error when passing a JS object to a <WebMethod()> function.

My Object was composed of EF entities which contained references to other entities. Setting those reference properties to nothing resolved this. No idea why this didn't cause a cyclical reference when serializing to send to the JS, but there it is.

Yardage answered 21/2, 2019 at 18:37 Comment(0)
V
0

FWIW, this is the code I use:

public static PropertyInfo GetUnambiguousProperty(object component, string name, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance) => GetUnambiguousProperty(component?.GetType(), name, flags);
public static PropertyInfo GetUnambiguousProperty(Type type, string name, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance)
{
    if (type == null)
        throw new ArgumentNullException(nameof(type));

    if (name == null)
        throw new ArgumentNullException(nameof(name));

    return type.GetProperties(flags).Where(p => p.Name == name).FirstOrDefault();
}
Valenba answered 23/2, 2021 at 11:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.