AmbiguousMatchException - Type.GetProperty - C#Reflection

时间:2009-06-15 06:19:05

标签: c#

昨天我在开发Web部件时遇到了一个问题(这个问题不是关于webpart而是关于C#)。关于问题的小背景。我有一个使用Reflection加载WebPart的代码,其中我得到了AmbiguousMatchException。要重现它,请尝试以下代码

        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

我想知道BindingFlag来获取高度属性。您将有一个问题,我为什么要创建另一个已经存在于Base类中的Height属性。这就是设计Microsoft.SharePoint.WebPartPages.PageViewerWebPart的方法,检查PageViewerWebPart类的Height属性。

4 个答案:

答案 0 :(得分:13)

那里有两个Height属性,它们的都不是由Class1声明的,您正在调用GetProperty

现在,说你正在寻找“尽可能远离类型层次结构的高度属性”是否公平?如果是这样,这里有一些代码可以找到它:

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

请注意,如果您知道,则返回类型会有所不同,可能值得简化代码,如sambo99's answer所示。这会使它变得非常脆弱 - 稍后更改返回类型可能会导致只能在执行时发现的错误。哎哟。我说,到你这样做的时候,你仍处于一种脆弱的境地:)

答案 1 :(得分:3)

请参阅以下示例:

    class Foo {
        public float Height { get; set; }
    }

    class Bar : Foo {
        public int Height { get; set; }
    }

    class BarBar : Bar { }

    class Foo2 : Foo{
        public float Height { get; set; }
    }

    class BarBar2 : Foo2 { } 

    static void Main(string[] args) {

        // works 
        var p = typeof(BarBar).GetProperty("Height", typeof(float), Type.EmptyTypes);

        // works
        var p2 = typeof(BarBar).BaseType.GetProperty("Height", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);

        // works
        var p3 = typeof(BarBar2).GetProperty("Height");

        // fails
        var p4 = typeof(BarBar).GetProperty("Height"); 

        Console.WriteLine(p);

    }
  • 如果两个或多个具有不同返回类型且同名的属性存在于您的继承链中,则会出现AmbiguousMatchException。

  • 如果覆盖实现(使用new或override)并保持返回类型,则Stuff会解决。

  • 您只能强制反射以查看特定类型的属性。

答案 2 :(得分:2)

显然,有两个属性与您给出的“Height”名称相匹配,一个名称返回类型为int,另一个字符串。另外,只需将返回类型作为GetPropertyCall的第二个参数添加,具体取决于您要返回的内容和这种模糊性应该消失。

答案 3 :(得分:0)

我创建了两个扩展方法,扩展了Jon Skeet的答案。您可以将它们放在任何公共静态类中。

编辑:删除了MissingMemberException,使其更像默认的.NET实现,在失败时返回null。

用法:

var field = type.GetFieldUnambiguous(type, "FieldName", bindingFlags);
var property = type.GetPropertyUnambiguous(type, "PropertyName", bindingFlags);

实现:

public static FieldInfo GetFieldUnambiguous(this Type type, string name, BindingFlags flags)
{
    if (type == null) throw new ArgumentNullException(nameof(type));
    if (name == null) throw new ArgumentNullException(nameof(name));

    flags |= BindingFlags.DeclaredOnly;

    while (type != null)
    {
        var field = type.GetField(name, flags);

        if (field != null)
        {
            return field;
        }

        type = type.BaseType;
    }

    return null;
}

public static PropertyInfo GetPropertyUnambiguous(this Type type, string name, BindingFlags flags
{
    if (type == null) throw new ArgumentNullException(nameof(type));
    if (name == null) throw new ArgumentNullException(nameof(name));

    flags |= BindingFlags.DeclaredOnly;

    while (type != null)
    {
        var property = type.GetProperty(name, flags);

        if (property != null)
        {
            return property;
        }

        type = type.BaseType;
    }

    return null;
}