介绍 C#中的接口提供了一种实现运行时的多态。通过接口可以使用相同接口的引用来访问实现相同接口的不同类的方法,其实是使用虚方法通过相同的引用调用相同基础的不同的类。在开始前先使用简单的短类例子来解释接口的概念,下面的简短的例子显示接口的样子。
P1.cs
class Demo { public static void Main() { System.Console.WriteLine("Hello Interfaces"); } }
interface abc { }
输出:
编译运行上面的程序运行程序并显示出期望的结果。这段程序包含一个Demo类程序入门Main()方法中打印“Hello Interfaces”。在上面的程序中还定义了接口abc。abc接口是空的,可以在接口中添加一些元素。
P2.cs
class Demo { public static void Main() { System.Console.WriteLine("Hello Interfaces"); } }
interface abc { int x; }
输出:
P2.cs(11,3): error CS0525: Interfaces cannot contain fields |
错误!在C#的接口中不能包含字段例如变量。上面的程序在接口abc中声明了一个整型变量x。编译将会出错。
P3.cs
class Demo { public static void Main() { System.Console.WriteLine("Hello Interfaces"); } }
interface abc { void xyz() { System.Console.WriteLine("In xyz"); } }
输出:
P3.cs(11,8): error CS0531: 'abc.xyz()': interface members cannot have a definition |
这次在接口中定义了xyz()方法C#编译器发现了错误。这说明在接口中成员不能有定义。也就意味着如果在接口abc中仅仅只有方法的声明编译器将认为正确?
P4.cs
class Demo { public static void Main() { System.Console.WriteLine("Hello Interfaces"); } }
interface abc { void xyz(); }
输出:
上面的程序编译运行正常产生期望的输出结果。最后编译成功。在C#的接口中仅仅包含方法的定义。现在看看方法的作用。
接口是类实现的规范。也就是说接口规定了方法的原型并有类来实现接口所定义的方法原型。
因此在类Demo和接口abc结合在一起。
P5.cs
class Demo : abc { public static void Main() { System.Console.WriteLine("Hello Interfaces"); } }
interface abc { void xyz(); }
输出:
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
class Demo : abc { public static void Main() { System.Console.WriteLine("Hello Interfaces"); }
void xyz() { System.Console.WriteLine("In xyz"); } }
interface abc { void xyz(); }
输出:
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。看下面的代码。
P7.cs
class Demo : abc { public static void Main() { Demo demo = new Demo(); System.Console.WriteLine("Hello Interfaces"); demo.xyz(); }
public void xyz() { System.Console.WriteLine("In xyz"); } }
interface abc { void xyz(); }
输出:
好的!上面的代码编译运行成功产生预期的输出结果。正如前面提及的接口可以调用实现相同的接口的不同的类。因此,需要不同的实现相同接口的类。在上面的代码中类Demo实现了接口abc。下面让另一个类Sample也实现接口abc。
P8.cs
class Demo : abc { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); refDemo.xyz(); Sample refSample = new Sample(); refSample.xyz(); }
public void xyz() { System.Console.WriteLine("In Demo :: xyz"); } }
interface abc { void xyz(); }
class Sample : abc { public void xyz() { System.Console.WriteLine("In Sample :: xyz"); } }
输出:
In Demo :: xyz In Sample :: xyz
|
上面的程序编译运行成功生产期望的输出结果。refDemo是类Demo的实例。refSample是类Sample的实例。这两个类都实现了接口abc因此他们都实现了方法xyz()。从程序入口Main()方法中通过refDemo和refSample实例分别调用了类Demo和类Sample的xyz()方法。
现在有两个不同的类实现了相同的接口此时显示了如何从不同的类中使用相同的接口引用。
P9.cs
class Demo : abc { public static void Main() { System.Console.WriteLine("Hello Interfaces"); abc refabc = null; refabc = new Demo(); refabc.xyz(); refabc = new Sample(); refabc.xyz(); }
public void xyz() { System.Console.WriteLine("In Demo :: xyz"); } }
interface abc { void xyz(); }
class Sample : abc { public void xyz() { System.Console.WriteLine("In Sample :: xyz"); } }
输出:
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
class Demo : abc { public static void Main() { abc[] refabc = { new Demo(), new Sample() }; for(int i = 0; i <= 1; i++) refabc[i].xyz(); }
public void xyz() { System.Console.WriteLine("In Demo :: xyz"); } }
interface abc { void xyz(); }
class Sample : abc { public void xyz() { System.Console.WriteLine("In Sample :: xyz"); } }
输出:
In Demo :: xyz In Sample :: xyz
|
上面的代码编译运行程序产生了预期的输出结果。refabc是一个类型为abc接口的数组。它保存了类Demo和Sample的对象的引用。在for循环中,使用数字refabc,可以调用类Demo和Sample中的方法xyz()。一个类可以实现多个接口。看下面的程序。
P11.cs
class Demo : abc, def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); abc refabc = new Demo(); refabc.xyz(); }
public void xyz() { System.Console.WriteLine("In xyz"); }
public void pqr() { System.Console.WriteLine("In xyz"); } }
interface abc { void xyz(); }
interface def { void pqr(); }
输出:
上面的代码编译运行程序产生了预期的输出结果。类Demo实现了接口abc并且实现了xyz()方法。类Demo也实现了def接口也实现了pqr()方法。refabc是类型为abc接口的变量是类Demo的实例。可以通过refabc的实例调用Demo中xyz()方法就像refabc是接口abc的类型包含了xyz()方法的原型
P12.cs
class Demo : abc, def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); abc refabc = new Demo(); refabc.xyz(); refabc.pqr(); }
public void xyz() { System.Console.WriteLine("In xyz"); }
public void pqr() { System.Console.WriteLine("In xyz"); } }
interface abc { void xyz(); }
interface def { void pqr(); }
输出:
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()的原型。下面的程序代码将这样实现。
P13.cs
class Demo : abc, def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); abc refabc = refDemo; refabc.xyz(); def refdef = refDemo; refdef.pqr(); }
public void xyz() { System.Console.WriteLine("In xyz"); }
public void pqr() { System.Console.WriteLine("In pqr"); } }
interface abc { void xyz(); }
interface def { void pqr(); }
输出:
Hello Interfaces In xyz In pqr
|
上面的代码编译运行程序产生了预期的输出结果。类Demo实现了接口abc和def。一个类Demo的对象创建并将引用存储在refDemo中。refabc是类型为接口abc的变量指向类Demo的实例。在Deom中的xyz()方法可以通过refabc来方法因为refabc是接口abc的变量接口abc包含了方法xyz()的原型。同样,refdef是类型为def的变量指向类Demo的实力。可以通过refdef来方法Demo中的pqr()方法,因为refdef是类型为接口def的变量,接口def中包括了方法pqr()的原型。
P14.cs
class Demo : abc, def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); abc refabc = refDemo; refabc.xyz(); def refdef = refDemo; refdef.xyz(); }
public void xyz() { System.Console.WriteLine("In xyz"); } }
interface abc { void xyz(); }
interface def { void xyz(); }
输出:
Hello Interfaces In xyz In xyz
|
上面的代码编译运行程序产生了预期的输出结果。接口abc和def都定义了方法xyz()的原型。类Demo实现接口abc和def并也实现了xyz()的方法。因此可以通过接口变量(refabc或refdef)存储在refabc或refdef的Demo的对象引用来访问方法xyz()。假设一个问题,实现接口abc中的xyz()的方法和实现接口def中的xyz()的方法是不同的在类Demo中如何实现?此时需要按下面的程序使用完全限定名来实现。
P15.cs
class Demo : abc, def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); abc refabc = refDemo; refabc.xyz(); def refdef = refDemo; refdef.xyz(); }
public void abc.xyz() { System.Console.WriteLine("In abc.xyz"); }
public void def.xyz() { System.Console.WriteLine("In def.xyz"); }
}
interface abc { void xyz(); }
interface def { void xyz(); }
输出:
a.cs(13,15): error CS0106: The modifier 'public' is not valid for this item a.cs(18,15): error CS0106: The modifier 'public' is not valid for this item
|
失败!使用了全缀名得到错误。原因是当为接口中的部分方法原型使用全缀名是,编译器不能使用想public的修饰符。因此从上面的代码中去掉public。
P16.cs
class Demo : abc, def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); abc refabc = refDemo; refabc.xyz(); def refdef = refDemo; refdef.xyz(); }
void abc.xyz() { System.Console.WriteLine("In abc.xyz"); }
void def.xyz() { System.Console.WriteLine("In def.xyz"); }
}
interface abc { void xyz(); }
interface def { void xyz(); }
输出:
Hello Interfaces In abc.xyz In def.xyz
|
上面的代码编译运行程序产生了预期的输出结果。系统允许定义接口有相同的方法原型使使用全缀名。在上面的例子中,接口abc和def包含相同的方法原型xyz()。类Demo实现了上面两个接口。在实现方法xyz()可以使用全缀名来制定实现接口abc中的方法xyz()方法还是实现接口def中的xyz()方法。
P17.cs
class Demo : def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); def refdef = refDemo; refdef.xyz(); refdef.pqr(); }
public void xyz() { System.Console.WriteLine("In xyz"); }
public void pqr() { System.Console.WriteLine("In pqr"); }
}
interface abc { void xyz(); }
interface def : abc { void pqr(); }
输出:
Hello Interfaces In xyz In pqr
|
上面的代码编译运行程序产生了预期的输出结果。接口支持继承。接口def从接口abc中继承了方法原型。类demo实先def接口。接口变量refdef存储了类Demo的对象的引用。可以通过接口变量refdef的引用来访问类Demo中的xyz()和pqr()方法。接口def继承自接口abc思考如何使用xyz()和pqr()的全缀名。
P18.cs
class Demo : def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); def refdef = refDemo; refdef.xyz(); refdef.pqr(); }
void def.xyz() { System.Console.WriteLine("In xyz"); }
void def.pqr() { System.Console.WriteLine("In pqr"); }
}
interface abc { void xyz(); }
interface def : abc { void pqr(); }
输出:
P17.cs(12,8): error CS0539: 'def.xyz' in explicit interface declaration is not a member of interface P17.cs(29,11): (Location of symbol related to previous error) P17.cs(1,7): error CS0535: 'Demo' does not implement interface member 'abc.xyz()' P17.cs(26,8): (Location of symbol related to previous error)
|
失败!xyz方法原型是接口abc的原始成员。因此,即使接口def基础自接口abc,但方法xyz()的全缀名需要是abc.xyz而不是上面程序中的def.xyz。事实上,会获得编译错误。在下面代码中使用正确的全缀名来修复错误。
P19.cs
class Demo : def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); def refdef = refDemo; refdef.xyz(); refdef.pqr(); }
void abc.xyz() { System.Console.WriteLine("In xyz"); }
void def.pqr() { System.Console.WriteLine("In pqr"); }
}
interface abc { void xyz(); }
interface def : abc { void pqr(); }
输出:
Hello Interfaces In xyz In pqr
|
上面的代码编译运行程序产生了预期的输出结果。但在使用全缀名时有一些小的陷阱。
P20.cs
class Demo : def { public static void Main() { System.Console.WriteLine("Hello Interfaces"); Demo refDemo = new Demo(); refDemo.xyz(); refDemo.pqr(); }
void abc.xyz() { System.Console.WriteLine("In xyz"); }
void def.pqr() { System.Console.WriteLine("In pqr"); }
}
interface abc { void xyz(); }
interface def : abc { void pqr(); }
输出:
P19.cs(7,5): error CS0117: 'Demo' does not contain a definition for 'xyz' P19.cs(8,5): error CS0117: 'Demo' does not contain a definition for 'pqr'
|
上面代码是失败的。refDemo是类Demo的对象。可以通过refDemo调用xyz()方法。因为C#xyz()和ddd.xyz()是不相同的事情。abc.xyz()是存在的。xyz()不在类中。将得到错误信息说类Demo没有包含方法xyz()的定义。因为C#中abc.xyz()仅仅包含在类型abc接口的引用。相同的,def.pqr()仅能够通过类型为def的应用来调用。
转载原文地址:http://www.dingos.cn/index.php?topic=763.0(附件)
|
请发表评论