C# interface (接口基础知识详解)
Interface(接口)
(本文转载地址:http://blog.sina.com.cn/s/blog_574c993d0100d59n.html)
介绍:
C#中的接口提供了一种实现运行时的多态。通过接口可以使用相同接口的引用来访问实现相同接口的不同类的方法,其实是使用虚方法通过相同的引用调用相同基础的不同的类。
在开始前先使用简单的短类例子来解释接口的概念,下面的简短的例子显示接口的样子。
P1.cs 程序代码:
1 class Demo { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 } 5 } 6 7 interface abc { 8 }
输出:Hello Interfaces
编译运行上面的程序运行程序并显示出期望的结果。这段程序包含一个Demo类程序入门Main()方法中打印“Hello Interfaces”。在上面的程序中还定义了接口abc。abc接口是空的,可以在接口中添加一些元素。
P2.cs 程序代码:
1 class Demo { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 } 5 } 6 7 interface abc { 8 int x; 9 }
输出:P2.cs(11,3): error CS0525: Interfaces cannot contain fields
错误!在C#的接口中不能包含字段例如变量。上面的程序在接口abc中声明了一个整型变量x。编译将会出错。
P3.cs 程序代码:
1 class Demo { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 } 5 } 6 7 interface abc { 8 void xyz() { 9 System.Console.WriteLine("In xyz"); 10 } 11 }
输出:P3.cs(11,8): error CS0531: 'abc.xyz()': interface members cannot have a definition
这次在接口中定义了xyz()方法C#编译器发现了错误。这说明在接口中成员不能有定义。也就意味着如果在接口abc中仅仅只有方法的声明编译器将认为正确?
P4.cs 程序代码:
1 class Demo { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 } 5 } 6 7 interface abc { 8 void xyz(); 9 }
输出:Hello Interfaces
上面的程序编译运行正常产生期望的输出结果。最后编译成功。在C#的接口中仅仅包含方法的定义。现在看看方法的作用。接口是类实现的规范。也就是说接口规定了方法的原型并有类来实现接口所定义的方法原型。
因此在类Demo和接口abc结合在一起。
P5.cs 程序代码:
1 class Demo : abc { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 } 5 } 6 7 interface abc { 8 void xyz(); 9 }
输出:
P4.cs(1,7): error CS0535: 'Demo' does not implement interface member 'abc.xyz()' P4.cs(11,8): (Location of symbol related to previous error) |
在上面的代码中Demo和接口abc通过“demo : abc”联系在一起,通常对于这个结合有一点小的误会。类Demo需要负责定义接口abc中定义的方法原型。因此在上面代码中的Demo没有实现abc接口中定义的xyz的方法,上面的代码出错。为了修正问题,类Demo必须实现接口abc中定义的方法原型xyz。看下面的程序代码。
P6.cs 程序代码:
1 class Demo : abc { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 } 5 6 void xyz() { 7 System.Console.WriteLine("In xyz"); 8 } 9 } 10 11 interface abc { 12 void xyz(); 13 }
输出:
a.cs(1,7): error CS0536: 'Demo' does not implement interface member 'abc.xyz()'.'Demo.xyz()' is either static, not public, or has the wrong return type. a.cs(16,8): (Location of symbol related to previous error) a.cs(7,8): (Location of symbol related to previous error) |
又出现错误!类Demo实现了方法xyz但没有足够的访问权限。在接口abc定义的方法xyz的访问权限是public。看下面的代码。
1 class Demo : abc { 2 public static void Main() { 3 Demo demo = new Demo(); 4 System.Console.WriteLine("Hello Interfaces"); 5 demo.xyz(); 6 } 7 8 public void xyz() { 9 System.Console.WriteLine("In xyz"); 10 } 11 } 12 13 interface abc { 14 void xyz(); 15 }
Hello Interfaces In xyz |
好的!上面的代码编译运行成功产生预期的输出结果。正如前面提及的接口可以调用实现相同的接口的不同的类。因此,需要不同的实现相同接口的类。在上面的代码中类Demo实现了接口abc。下面让另一个类Sample也实现接口abc。
P8.cs 程序代码:
1 class Demo : abc { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 Demo refDemo = new Demo(); 5 refDemo.xyz(); 6 Sample refSample = new Sample(); 7 refSample.xyz(); 8 } 9 10 public void xyz() { 11 System.Console.WriteLine("In Demo :: xyz"); 12 } 13 } 14 15 interface abc { 16 void xyz(); 17 } 18 19 class Sample : abc { 20 public void xyz() { 21 System.Console.WriteLine("In Sample :: xyz"); 22 } 23 }
输出:
In Demo :: xyz In Sample :: xyz |
上面的程序编译运行成功生产期望的输出结果。refDemo是类Demo的实例。refSample是类Sample的实例。这两个类都实现了接口abc因此他们都实现了方法xyz()。从程序入口Main()方法中通过refDemo和refSample实例分别调用了类Demo和类Sample的xyz()方法。
现在有两个不同的类实现了相同的接口此时显示了如何从不同的类中使用相同的接口引用。
P9.cs 程序代码:
1 class Demo : abc { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 abc refabc = null; 5 refabc = new Demo(); 6 refabc.xyz(); 7 refabc = new Sample(); 8 refabc.xyz(); 9 } 10 11 public void xyz() { 12 System.Console.WriteLine("In Demo :: xyz"); 13 } 14 } 15 16 interface abc { 17 void xyz(); 18 } 19 20 class Sample : abc { 21 public void xyz() { 22 System.Console.WriteLine("In Sample :: xyz"); 23 } 24 }
输出:
In Demo :: xyz In Sample :: xyz |
上面的代码编译运行程序产生了预期的输出结果。在Main()方法中定义了接口引用refabc是接口abc类型。实例化为Demo在refabc中存储了类Demo类定义的xyz()可以通过refabc来调用。接下去,实例化为Sample在refabc中存储了类Sample类定义的xyz()可以通过refabc来调用。因此,可以通过共同的接口引用refabc来访问不同的类Demo和Sample中的xyz()的方法。在下面的代码中使用循环调用类Demo和Sample实现相同接口abc使用单一接口引用refabc类型匹配的接口abc的类的实现。
P10.cs 程序代码:
1 class Demo : abc { 2 public static void Main() { 3 abc[] refabc = { new Demo(), new Sample() }; 4 for(int i = 0; i <= 1; i++) 5 refabc[i].xyz(); 6 } 7 8 public void xyz() { 9 System.Console.WriteLine("In Demo :: xyz"); 10 } 11 } 12 13 interface abc { 14 void xyz(); 15 } 16 17 class Sample : abc { 18 public void xyz() { 19 System.Console.WriteLine("In Sample :: xyz"); 20 } 21 }
输出:
In Demo :: xyz In Sample :: xyz |
上面的代码编译运行程序产生了预期的输出结果。refabc是一个类型为abc接口的数组。它保存了类Demo和Sample的对象的引用。在for循环中,使用数字refabc,可以调用类Demo和Sample中的方法xyz()。一个类可以实现多个接口。看下面的程序。
P11.cs 程序代码:
1 class Demo : abc, def { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 abc refabc = new Demo(); 5 refabc.xyz(); 6 } 7 8 public void xyz() { 9 System.Console.WriteLine("In xyz"); 10 } 11 12 public void pqr() { 13 System.Console.WriteLine("In xyz"); 14 } 15 } 16 17 interface abc { 18 void xyz(); 19 } 20 21 interface def { 22 void pqr(); 23 }
输出:
Hello Interfaces In xyz |
上面的代码编译运行程序产生了预期的输出结果。类Demo实现了接口abc并且实现了xyz()方法。类Demo也实现了def接口也实现了pqr()方法。refabc是类型为abc接口的变量是类Demo的实例。可以通过refabc的实例调用Demo中xyz()方法就像refabc是接口abc的类型包含了xyz()方法的原型
P12.cs 程序代码:
1 class Demo : abc, def { 2 public static void Main() { 3 System.Console.WriteLine("Hello Interfaces"); 4 abc refabc = new Demo(); 5 refabc.xyz(); 6 refabc.pqr(); 7 } 8 9 public void xyz() { 10 System.Console.WriteLine("In xyz"); 11 } 12 13 public void pqr() { 14 System.Console.WriteLine("In xyz"); 15 } 16 } 17 18 interface abc { 19 void xyz(); 20 } 21 22 interface def { 23 void pqr(); 24 }
输出:
P11.cs(9,5): error CS0117: 'abc' does not contain a definition for 'pqr' |
错误!尝试通过定义为接口abc类型的变量refabc的Demo实例来访问pqr()方法,在接口abc中包含了函数xyz()的原型但没有包含pqr()方法原型。可以通过类型为接口def的Demo实例来方法pqr()方法因为接口def包含方法pqr()的原型。