【问题标题】:Unable to invoke base class method无法调用基类方法
【发布时间】:2014-01-09 06:59:56
【问题描述】:

无法调用基类的方法,

public class MyBaseClass
{
    public void PrintTheValue(int inputValue)
    {
        Console.WriteLine(" Printed from Base class method " + inputValue);
    }
}

public class MyDerivedClass : MyBaseClass
{
    public void PrintTheValue(long inputValue)
    {
        Console.WriteLine(" Printed from Derived class method " + inputValue);
    }
}

如果我尝试调用该函数,

public static void Main()
{ 
    long longValue = 5;
    int intValue = 6;
    MyDerivedClass derivedObj = new MyDerivedClass();
    derivedObj.PrintTheValue(longValue);
    derivedObj.PrintTheValue(intValue);
    Console.Read();
}

输出让我吃惊,

从派生类方法 5 打印
从派生类方法6打印

为什么我不能调用基类的函数?
我知道什么是重载和覆盖,我认为它应该调用基类方法,
我也尝试过显式转换,derivedObj.PrintTheValue((int)longValue); 但结果相同。

【问题讨论】:

    标签: c# overriding overloading


    【解决方案1】:

    相信你已经被困在Overloading Methods in a base class
    .NET 运行时处理这个问题的方式非常有趣,因为它总是支持最派生的编译时类型,这意味着它总是会尝试调用最接近调用的类的方法(适用于调用)方法。

    技术细节:
    根据Overload resolution 提到

    例如,方法调用的候选集不包括标记为覆盖的方法(第 7.3 节),如果派生类中的任何方法适用(第 7.5.5.1 节),则基类中的方法不是候选方法。

    进一步阅读详细描述可以发现,.net 通过Member lookup rules 构造了适用于method invocation 的候选方法,其中在方法调用中明确提到,

    • 构造方法调用的候选方法集。从与 M 相关联的一组方法开始,这些方法是通过先前的成员查找(第 7.3 节)找到的,该集合被缩减为适用于参数列表 A 的那些方法。集合缩减包括应用以下规则到集合中的每个方法 TN,其中 T 是声明方法 N 的类型:
      • 如果 N 不适用于 A(第 7.4.2.1 节),则从集合中删除 N。
      • 如果 N 适用于 A(第 7.4.2.1 节),则从集合中删除所有在 T 基类型中声明的方法。

    正如Applicable function member 中提到的那样

    当满足以下所有条件时,就称函数成员是关于参数列表 A 的适用函数成员:

  • A 中的参数数量与函数成员声明中的参数数量相同。
  • 对于A中的每个实参,实参的传参方式(即value、ref或out)与对应参数的传参方式相同,
    ---- 对于值形参或形参数组,存在从实参类型到对应形参类型的隐式转换(第 6.1 节),或者
  • ---- 对于 ref 或 out 参数,参数的类型与对应参数的类型相同。毕竟, ref 或 out 参数是传递参数的别名。

    上面的细节可以通过简单的例子来解释,

    public class VMBase
    {
        public int Add(int a, int b)
        {
            Console.WriteLine("Base class method invoked");
            return a + b;
        }
    }
    public class MyVMBase : VMBase
    {       
        public long Add(long a , long b)
        {
            Console.WriteLine("Derived class method invoked");
            return a + b;
        }    
    }
    
    public static void Main()
    {           
       MyVMBase myObj = new MyVMBase();
       int imy = 5;
       int j = 6;
       int myaddValue = myObj.Add(imy, j); //COMPILE TIME ERROR Cannot implicitly convert type 'long' to 'int'. An explicit conversion exists (are you missing a cast?) 
       long myaddValue2 = myObj.Add(imy, j);  // NO ERROR
     }  
    

    所以从上面的方法可以看出报了编译时错误,这意味着它总是会调用派生类的方法public long Add(long a , long b)

    【讨论】:

      【解决方案2】:

      @Prateek:原因是派生类接受 long 值,即使是整数值也能满足,因此您会看到基类永远不会被命中。

      为了了解您的代码的工作方式,我进行了如下所示的小修改。试试看。你会知道的...... :)

      public class MyBaseClass
      {
          public void PrintTheValue(long inputValue)
          {
              Console.WriteLine(" Printed from Base class method " + inputValue);
          }
      }
      
      public class MyDerivedClass : MyBaseClass
      {
          public void PrintTheValue(int inputValue)
          {
              Console.WriteLine(" Printed from Derived class method " + inputValue);
          }
      }
      
       static void Main(string[] args)
          {
              long longValue = 5;
              int intValue = 6;
              MyDerivedClass derivedObj = new MyDerivedClass();
              derivedObj.PrintTheValue(longValue);
              derivedObj.PrintTheValue(intValue);
              Console.Read();
          }
      

      输出会是这样..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-05
        • 2011-08-30
        • 1970-01-01
        • 2012-06-28
        • 2010-10-21
        • 2021-10-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多