Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AmbiguousMatchException - Type.GetProperty - C# Reflection

Tags:

c#

Yesterday I ran into an Issue while developing a Web Part (This question is not about webpart but about C#). Little background about the Issue. I have a code that load the WebPart using the Reflection, In which I got the AmbiguousMatchException. To reproduce it try the below code

        public class TypeA
        {
            public virtual int Height { get; set; }
        }
        public class TypeB : TypeA
        {
            public String Height { get; set; }
        }
        public class Class1 : TypeB
        {

        }

        Assembly oAssemblyCurrent = Assembly.GetExecutingAssembly();
        Type oType2 = oAssemblyCurrent.GetType("AmbigousMatchReflection.Class1");
        PropertyInfo oPropertyInfo2 = oType2.GetProperty("Height");//Throws AmbiguousMatchException 
        oPropertyInfo2 = oType2.GetProperty("Height", 
            BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);  // I tried this code Neither these BindingFlags or any other didnt help

I wanted to know the BindingFlag to Fetch the Height Property. You will have the question of why I wanted to create another Height Property that is already there in the Base class. That is how the Microsoft.SharePoint.WebPartPages.PageViewerWebPart was designed check the Height property of the PageViewerWebPart class.

like image 523
Kusek Avatar asked Jun 15 '09 06:06

Kusek


1 Answers

There are two Height properties there, and neither of them are declared by Class1 which you're calling GetProperty on.

Now, would it be fair to say you're looking for "the Height property declared as far down the type hiearchy as possible"? If so, here's some code to find it:

using System;
using System.Diagnostics;
using System.Reflection;

public class TypeA
{
    public virtual int Height { get; set; }
}

public class TypeB : TypeA
{
    public new String Height { get; set; }
}

public class Class1 : TypeB
{        
}

class Test
{
    static void Main()
    {
        Type type = typeof(Class1);
        Console.WriteLine(GetLowestProperty(type, "Height").DeclaringType);
    }

    static PropertyInfo GetLowestProperty(Type type, string name)
    {
        while (type != null)
        {
            var property = type.GetProperty(name, BindingFlags.DeclaredOnly | 
                                                  BindingFlags.Public |
                                                  BindingFlags.Instance);
            if (property != null)
            {
                return property;
            }
            type = type.BaseType;
        }
        return null;
    }
}

Note that if you know the return types will be different, it may be worth simplifying the code as shown in sambo99's answer. That would make it quite brittle though - changing the return type later could then cause bugs which would only be found at execution time. Ouch. I'd say that by the time you've done this you're in a brittle situation anyway :)

like image 154
Jon Skeet Avatar answered Oct 12 '22 03:10

Jon Skeet