代码之家  ›  专栏  ›  技术社区  ›  Kusek

含糊不清的匹配异常-type.getproperty-c反射

c#
  •  6
  • Kusek  · 技术社区  · 16 年前

    昨天我在开发Web部件时遇到了一个问题(这个问题不是关于Web部件,而是关于C)。关于这个问题的背景很少。我有一个使用反射加载Web部件的代码,在其中我得到了含糊不清的MatchException。要复制它,请尝试以下代码

            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
    

    我想知道绑定标志以获取Height属性。你会问我为什么要创建另一个已经存在于基类中的高度属性。就是这样 Microsoft.SharePoint.WebPartPages.PageViewerWebPart 已设计检查PageViewerWebPart类的高度属性。

    4 回复  |  直到 7 年前
        1
  •  13
  •   Community Mohan Dere    8 年前

    有两个 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 . 这将使它非常脆弱——稍后更改返回类型可能会导致只在执行时发现的错误。哎哟。我想说的是,当你这样做的时候,你已经处于一个脆弱的境地:)

        2
  •  3
  •   Sam Saffron James Allen    16 年前

    请参见以下示例:

        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);
    
        }
    
    • 如果两个或多个属性具有 不同的 返回类型和 同名 生活在你的继承链中。

    • 如果您重写一个实现(使用new或override)并维护返回类型,那么stufacture就可以解决问题。

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

        3
  •  2
  •   Tetraneutron    16 年前

    显然,有两个属性与您给定的“height”名称相匹配,一个属性的返回类型为int,另一个属性的字符串。只需将返回类型作为第二个参数添加到getPropertyCall中,这取决于您要返回的对象,这种模糊性应该会消失。

        4
  •  0
  •   Lazlo    7 年前

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

    编辑:删除 MissingMemberException 更像默认的.NET实现,失败时返回空值。

    用途:

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