8

我有以下代码:

 interface ICalculator
 {
     int Sum ( int x,  int y);
 }

 abstract class AbsCalculator
 {
     public abstract int Sum(int x, int y);
 }

 class Calculator : AbsCalculator, ICalculator
 {
     public override int Sum(int x, int y)
     {
         Console.WriteLine ( "From overriden method" );
         return x + y;
     }
 }

尽管我没有实现接口,但以下语句工作正常并且程序编译:

Calculator calculator = new Calculator();
Console.WriteLine ( calculator.Sum(10, 20) );

所以我的第一个问题是:它为什么起作用?

然后,我将以下接口实现添加到 Calculator 类:

int ICalculator.Sum(int x, int y)
{
     Console.WriteLine("From implemented method");
     return x + y;
}

再次尝试以下语句时:

Calculator calculator = new Calculator();
Console.WriteLine ( calculator.Sum(10, 20) );

从抽象中重写的方法仍然被调用。所以我的第二个问题是:为什么程序从抽象类调用方法而不是从接口调用方法?

4

3 回答 3

5

在 C# 中实现接口有两种方法,显式或隐式,但 CLR 只有一种实现类型 - 显式实现。

当 C# 编译器看到一个类必须实现一个接口时,它会查找与该接口所需类的签名匹配的方法,并指示 CLR 这些是实现,以节省您的代码。

因此,在您的情况下,当 C# 编译器看到您的类实现 ICalculator 时,它将查找与 Sum(int, int) 签名匹配的公共方法,并将该方法视为实现。该方法被覆盖的事实并不重要。

如果你想给方法的实现赋予另一种意义,你应该明确地赋予它。

于 2013-11-02T08:02:51.817 回答
4

不,你践踏它!您的第一个代码块是完全合法的。名称和签名与接口要求相匹配:int Sum(int x, int y).

现在,像这样的签名int ICalculator.Sum(int x, int y)称为显式接口实现,这意味着您只能通过接口类型的引用来访问该方法。

interface ICalculator {
    int Sum ( int x,  int y);
}

abstract class AbsCalculator {
    public abstract int Sum(int x, int y);
}

class Calculator : AbsCalculator, ICalculator {
    public override int Sum(int x, int y) {
        Console.WriteLine ( "From overriden method" );
        return x + y;
    }

    int ICalculator.Sum(int x, int y) {
         Console.WriteLine("From explicitly implemented interface method");
         return x + y;
    }
}

class Program {
    static void Main() {
        Calculator calculator = new Calculator();
        ICalculator icalc = calculator;

        // These calls will print different messages.
        calculator.Sum(10,20);
        icalc.Sum(10,20);
    }
}
于 2013-11-02T07:18:01.080 回答
4

回答你的第一个问题

在.NET中,当加载类型(类)时,CLR会创建一个方法表,该表包含类定义的方法和类继承的方法的条目,因此在您的情况下,Calculator该类包含以下条目

  1. 默认情况下,每个类都隐式继承自基Object类,因此方法表包含该类定义的每个虚拟实例方法的条目Object

  2. 您的类继承自AbsCalculator抽象类,因此方法表定义了抽象类方法的条目Sum

  3. 您的类继承了ICalculator接口,因此方法表定义了接口Sum方法的条目。

在这里,C# 编译器假设您正在实现接口方法,因为该方法是Public并且接口方法和抽象类方法的签名相同。所以编译器没有给出任何错误

回答你的第二个问题

在实现时有两个概念Implicit Interface Method ImplementationExplicit Interface Method Implementation

Implicit Interface Method Implementation我们使用接口引用调用接口方法时,如下所示

    Calculator calculator = new Calculator();
    ICalculator icalc = calculator;

    calculator.Sum(5,5);
    icalc.Sum(5,10);

当您在Explicit Interface Method Implementation方法名称前加上接口名称时,它就成为显式方法实现。

interface ICalc
{
    int Sum(int x, int y);
}

abstract class AbsCalc
{
    public abstract int Sum(int x, int y);
}

class Program : AbsCalc, ICalc
{
    public override int Sum(int x, int y)
    {
        Console.WriteLine("From abstract Override");
        return x + y;
    }

    int ICalc.Sum(int x,int y)
    {
        Console.WriteLine("From Intrface");
        return x + y;
    }


    static void Main(string[] args)
    {
        Program p = new Program();
        p.Sum(1, 2);

        ICalc i = p;
        i.Sum(1,2);
    }
}
于 2013-11-02T08:31:49.283 回答