为什么编译器选择了错误的方法重载

本文关键字:方法 重载 错误 编译器 选择 为什么 | 更新日期: 2023-09-27 18:32:46

我有一个简单的方法:

public void CacheDelegate(Object obj, MemberInfo memberInfo)
{
   switch (memberInfo.MemberType)
   {
    case MemberTypes.Field:
       var fieldInfo = (FieldInfo) memberInfo;
       CacheDelegate(obj, fieldInfo);
       break;
    case MemberTypes.Property:
       var propertyInfo = (PropertyInfo) memberInfo;
       CacheDelegate(obj, propertyInfo);
       break;
    case MemberTypes.Method:
       var methodInfo = (MethodInfo) memberInfo;
       CacheDelegate(obj, methodInfo);
       break;
    default:
       throw new Exception("Cannot create a delegate for MemberInfo provided.");
    }
}

上面的方法解析 memberInfo 的类型,并从下面调用适用的方法:

public void CacheDelegate(Object obj, FieldInfo fieldInfo)
{
   // Do stuff...
}
public void CacheDelegate(Object obj, PropertyInfo propertyInfo)
{
   // Do stuff...
}
public sealed override void CacheDelegate(Object obj, MethodInfo methodInfo)
{
   // Do stuff...
}

问题是最后一个案例标签 case MemberTypes.Method 不会使用方法信息重载调用 CacheDelegate 方法,而是使用成员信息重载调用 CacheDelegate!所以它基本上只是一遍又一遍地递归地调用自己。我尝试在调用方法时指定参数名称 methodInfo:methodInfo,但随后 Unity 引擎告诉我最好的重载方法不包含名为 methodInfo 的参数。

我很不明白为什么会发生这种情况。任何帮助将不胜感激。

为什么编译器选择了错误的方法重载

重载解析的工作原理如下。

从调用 on 的类型开始,查找在该类型上声明的可以使用的方法集。

如果该集为空,则尝试对声明的基类型或接口执行相同的操作。继续向上移动层次结构,直到找到至少一个匹配的方法,否则出错。

在找到的集合中,使用最具体的方法。如果是平局,则出错。

因此,在这四种方法中,有三种是在此类中声明的。在这三者中,有两种不适用。这样就只剩下public void CacheDelegate(Object obj, MemberInfo memberInfo)明确要调用的正确类,因此将其调用。

您可以使用((BaseType)this).CacheDelegate(obj, methodInfo);来强制调用所需的调用,因为基类型只有一个CacheDelegate重载可供选择。

Jon Hanna 已经解释了为什么会发生这种情况,我将通过提供源代码规范来补充,您可以在其中阅读详细信息:https://msdn.microsoft.com/en-us/library/aa691336(v=vs.71(.aspx

以下是解决问题的几种方法:

  • 不要重写或重载该方法,请使用其他名称。
  • 不要覆盖该方法,使用不同的参数重载,例如添加object ignoreMe。这将迫使重载兼容,但大多数人会同意它远非优雅。
  • 不要重写,而是使用 new 隐藏方法。当涉及方法隐藏时,我不是 100% 确定重载解决方案是如何工作的,但它应该导致它使用正确的方法。请记住,这样做当然会消除它的多态性。
  • 使用反射手动查找正确的重载,并调用它。这是最混乱的一个,也是开销最大的。这可能是也可能不是问题,具体取决于您的情况。但是,如果您真的想使用确切的覆盖/重载组合,它是唯一保留完全多态性的解决方案。