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

时间:2016-02-02 00:14:05

标签: c# unity3d polymorphism

我有这个简单的方法:

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,没有使用Method Info重载调用CacheDelegate方法,而是调用带有Member Info重载的CacheDelegate!所以它基本上只是一遍又一遍地反复呼唤自己。我在调用方法时尝试指定参数名称methodInfo:methodInfo,但Unity引擎告诉我最好的重载方法不包含名为methodInfo的参数。

我完全不知道为什么会这样。 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:4)

过载分辨率的工作原理如下。

从名为on的类型开始,找到可在该类型上声明的方法集。

如果该集合为空,则尝试使用基本类型或声明的接口。继续向上移动层次结构,直到找到至少一个匹配的方法,否则错误。

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

因此,在这四个方法中,有三个在这个类中声明了。其中三个不适用。只留下public void CacheDelegate(Object obj, MemberInfo memberInfo)作为要调用的正确类,因此调用它。

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

答案 1 :(得分:1)

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

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

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