在使用反射的GetProperty方法获取新属性时出现“找到多个匹配项”错误

42

如何获取我的属性?目前出现了Ambiguous match found的错误,请参见代码中的注释行。

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
}

1
运行时错误还是编译时错误? - Nikhil Agrawal
1
@Valamas请重新考虑所选答案。许多人会使用条件结构,例如 if (winform.GetType().GetProperty("Items") != null) {..} 在这种情况下,只需使用Linq切换异常... - Lorenz Lo Sauer
8个回答

49

Type.GetProperty

当出现AmbiguousMatchException异常的情况是...

...衍生类型通过使用new修饰符声明一个隐藏了同名继承属性的属性

如果您运行以下代码:

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

你会发现返回了两个PropertyInfo对象。一个是针对 MyBaseEntity ,另一个是针对 MyDerivedEntity。这就是为什么你会收到“找到模糊匹配”错误的原因。

你可以像这样获取 MyDerivedEntityPropertyInfo

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

2
+1。很好的实践解释。我已经添加了RTFM链接以防万一。 - Alexei Levenkov
1
太棒了!我将其简化为 type.GetProperties().First(p => p.Name == "MyEntity") 所有测试都通过了! - Valamas
1
无论是“First”还是“Single”,在没有元素的情况下都会引发异常 - Lorenz Lo Sauer
4
不如下一个回答好,因为你被迫使用类型名称。这并非总是可能的。 - monstr
2
我会匹配DeclaringType而不是PropertyType,这样您就可以指定要匹配属性的类,因为在某些情况下它们可能具有相同的类型。 - Michael Brown

39

对于属性:

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

针对该方法:

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

BindingFlags.DeclaredOnly - 指定仅考虑在提供的类型层次结构级别声明的成员。不会考虑继承的成员。


3
我不明白为什么这不是最受赞的答案,因为它是唯一安全的解决方案,因为第一个答案尝试匹配返回类型而不是使用简单的标志。 - Sasino

25

由于 MyDerivedEntity 中的 new 声明,会导致歧义。要解决这个问题,您可以使用 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();

如果派生类型中存在该属性,则会获取该属性,否则会获取基础类型中的该属性。如果需要,这可以很容易地反转。


1
这确实是一种更通用和可扩展的解决方案。 - it3xl
3
非常高效的解决方案!但我担心属性的顺序不能得到保证:M:System.Type.GetProperties 方法不会按照特定顺序返回属性,例如按字母顺序或声明顺序。您的代码不能依赖于属性返回的顺序,因为该顺序可能会变化。(摘自 MSDN文档 - KnorxThieus
比起排名靠前的广泛接受答案,这是一个更好、更通用的解决方案。 - Vasudevan Kannan
这是最好的答案,因为您可以决定是更喜欢“新”属性还是基类的属性。 - Emperor Eto

11

Kevin已经指出了问题,但你不需要复杂的语句或LINQ:

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

1

我在浏览器控制台中遇到了这个错误,我搜索了一下发现这个异常是针对C#的,答案也是针对C#的,然后我尝试查看我的代码,找到了问题出现的地方:

我有一个ajax post方法,当我提交数据时,就会出现这个错误,所以我传递的数据将被C# Web方法收集,因此当我查看该模型时,我有2个具有相同名称的属性,所以我删除了其中一个,问题和异常得到了解决。


0
我在使用MsgPack序列化我的LocationKey对象时遇到了问题。最终发现是我在LocationKey类中定义的运算符引起的。由于同时定义了这两个运算符,当尝试进行序列化时,DefaultContext.GetSerializer(obj.GetType());会抛出“找到多个匹配项”的异常。删除其中一个运算符后,问题得以解决。
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;
}

0

对我来说,在VB.Net中,当将JS对象传递给<WebMethod()>函数时,我遇到了这个超级描述性的错误。

我的对象由包含对其他实体的引用的EF实体组成。将这些引用属性设置为nothing解决了这个问题。不知道为什么在序列化发送到JS时,这没有导致循环引用,但就是这样。


0

顺便说一下,这是我使用的代码:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接