gpt4 book ai didi

.net - 谁能向我解释以下代码为何引发System.Reflection.AmbiguousMatchException?

转载 作者:行者123 更新时间:2023-12-03 14:52:47 27 4
gpt4 key购买 nike

using System;
using System.Reflection;

namespace A
{
interface IObjectWithId<TId>
{
TId Id { get; }
}
interface IEntityBase : IObjectWithId<object>
{
new object Id { get; }
}
abstract class BusinessObject<TId> : IObjectWithId<TId>
{
public abstract TId Id { get; }
}
class EntityBase : BusinessObject<object>, IEntityBase
{
public override object Id { get { return null; } }
}

public static class Program
{
public static void Main()
{
Console.WriteLine(typeof(EntityBase).GetProperty("Id", BindingFlags.Instance | BindingFlags.Public));
}
}
}


我得到这个:

System.Reflection.AmbiguousMatchException was unhandled
Message="Ambiguous match found."
Source="mscorlib"
StackTrace:
at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetProperty(String name, BindingFlags bindingAttr)
at A.Program.Main() in C:\Home\work\A\Program.cs:line 26
InnerException:



Microsoft Visual Studio 2008年
版本9.0.30729.1 SP
Microsoft .NET Framework
版本3.5 SP1


编辑:

奇怪的是,看起来其他人无法复制它。虽然它确实每次都会在我的机器上崩溃。我发现这段代码:

Console.WriteLine(typeof(EntityBase).GetProperty("Id", BindingFlags.Instance | BindingFlags.Public, null, typeof(object), Type.EmptyTypes, null));


可以正常运行,尽管应该相同。

最佳答案

为了让您的问题得到解答,我会让您熟悉术语“方法表”。这是.NET框架中类型的内部表示的一部分,其中每个.NET类型都有自己的方法表。您可以将其想象为包含该类型的所有方法和属性的哈希图(或字典)。关键是方法/属性签名(方法名称和参数类型,没有返回类型),值是匹配的方法/属性的集合,以及一些反射元数据信息,例如哪种类型声明了方法/属性。

当类A从基类-B派生或实现接口C时,BC方法表中的项目可直接在A方法表中使用。如果A的方法表已包含具有某些签名的项目,则该项目将添加到具有相同签名的集合中,因此A现在将具有该签名指向的2个方法/属性。区分这些重复条目的唯一方法是比较描述描述签名的类型的元数据。

让我们使用定义属性IObjectWithId<TId>的接口TId ID { get; set; }EntityBase类实现IObjectWithId<TId>,因此为其方法表接收一个TId ID { get; set; }属性。同时,此类实现IEntityBase接口,该接口为其赋予Object ID { get; set; }属性。然后,EntityBase类将在同一签名下接收两个属性(因为返回类型不参与签名),而它仍将公开两个不同的属性。以下声明将导致编译错误:

   public class EntityBase : IEntityBase, IObjectWithId<int>
{
public int ID { get; set; }
}


因为未实现 IEntityBase。同样,跟随也会失败:

   public class EntityBase : IEntityBase, IObjectWithId<int>
{
public object ID { get; set; }
}


因为这次 IObjectWithId<int>不满意。您可以尝试这样做:

   public class EntityBase : IEntityBase, IObjectWithId<int>
{
public object ID { get; set; }
public int ID { get; set; }
}


只是因为具有2个具有相同签名的属性而收到另一个编译错误。

解决此问题的方法是显式实现至少一个冲突的签名:

   public class EntityBase : IEntityBase, IObjectWithId<int>
{
private object objID;
private int intID;

object IEntityBase.ID { get { return objID; } set { objID = value; } }
int IObjectWithId<int>.ID { get { return intID; } set { intID = value; } }
}


现在,回到您的代码-您使用了 object而不是 TId,这会产生一种罕见但有趣的情况-这两个 ID属性由于其相同的签名而统一。所以这个课:

   public class EntityBase : IEntityBase, IObjectWithId<object>
{
public object ID { get; set; }
}


将编译,因为 ID属性同时满足两个接口。但是, EntityBase类在其方法表中仍具有两个 ID属性(每个接口都来自一个属性)。编译器会在 EntityBase类中将这两个属性自动分配给同一实现(此过程称为统一)。

如下代码:

typeof(EntityBase).GetProperty(
"ID", BindingFlags.Instance | BindingFlags.Public);


将查看 EntityBase类的方法表,并将看到该签名的两个属性条目,并且不知道该选择哪个。

这是因为您可能已经实现了这样的类:

   public class EntityBase : IEntityBase, IObjectWithId<object>
{
private object objID1;
private int objID2;

object IEntityBase.ID
{
get { return objID1; }
set { objID1 = value; }
}

object IObjectWithId<object>.ID
{
get { return objID2; }
set { objID2 = value; }
}
}


参见-这两个属性可以具有不同的实现,此时运行时无法知道它们的实现是否统一(反射发生在运行时,而不是执行统一时的编译时)。您收到的 AmbiguousMatchException是.NET框架阻止您执行可能具有未知/意外行为的代码的方法。

当没有为每个接口提供不同的实现时(如您的情况),该签名的方法表中的两个条目将调用您拥有的唯一实现,但是仍然有两个条目指向同一属性。为避免框架混乱,您应该在继承层次结构中使用足够高的类型,以便它的方法表中只有一个要反映的成员条目。在我们的示例中,如果在反映 Id属性时改用接口类型,则将解决情况,因为每个接口的方法表中只有一个用于请求签名的条目。

然后,您可以使用

Console.WriteLine(
typeof(IEntityBase).GetProperty(
"Id", BindingFlags.Instance | BindingFlags.Public));


要么

Console.WriteLine(
typeof(BusinessObject<object>).GetProperty(
"Id", BindingFlags.Instance | BindingFlags.Public));


取决于要检索的实现。在我的最新示例中,每个接口都有不同的实现,您可以通过选择正确的接口来调用反射的任何实现。在问题示例中,您可以使用所需的任何接口,因为两者都有一个实现。

关于.net - 谁能向我解释以下代码为何引发System.Reflection.AmbiguousMatchException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2745853/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com