Microsoft.Net框架程序设计学习笔记(22):接口与完全限定接口名技巧

  接口仅仅是一个包含着一组虚方法的抽象类型。

  接口中也可以定义事件、无参属性、含参属性(即索引器),因为它们都不过是映射到方法上的语法缩写而已。

  接口类型的名称要加一个大写的字母I前缀。接口定义允许使用修饰符--如public、protected、private、internal。

  一个值类型可以实现一个或多个接口,但当我们将一个值类型实例转型为一个接口类型时,该值类型实例必须被执行装箱。因为接口总被认为是引用类型,且它们定义的方法总是虚方法。未装箱的值类型没有指向类型方法表的指针。

  当我们创建可扩展的应用程序时,接口应该处于中心位置。假设我们正在编写一个应用程序,且希望其他人创建的类型能被我们的应用程序无缝地加载使用。下面就提供了设计这样的应用程序的方法。

  1. 创建一个程序集,然后在其中定义接口,接口的方法将用于应用程序和插件组件的通信机制。在为接口方法定义参数和返回值时,我们应该尽可能地使用定义在MSCorLib.dll中的其他接口和类型。如果确实希望传递或返回我们自己定义的数据类型时,则应该把它们也定义在该程序集中。一旦建立好接口定义后,我们应该给该程序集指定一个强命名,然后将其打包并部署到合作伙伴和用户那里。这样以后就把该程序集视作一个恒定不变的程序集。
  2. 创建一个单独的程序集用于包含我们的应用程序所使用的其他类型。该程序集引用到前一个程序集中定义的接口和类型。我们可以任意改变该程序集中的代码,而不会影响到接口,这样对插件开发人员不会造成任何影响。
  3. 插件开发人员会在他们的程序集中定义自己的类型,也将会引用到我们前面定义的接口程序集中的类型。插件开发人员也可以随时提供新版程序集,而不影响到我们的程序集。

使用接口改变已装箱值类型中的字段

  我们可以利用接口来欺骗C#使其改变已装箱类型中的字段。

  代码示例:

   
     
// 定义Change方法接口
interface IChangeBoxedPoint
{
void Change( int x, int y);
}

struct Point : IChangeBoxedPoint
{
public int x, y;

public void Change( int x, int y)
{
this .x = x;
this .y = y;
}

public override string ToString()
{
return String.Format( " ({0}, {1}) " , x, y);
}
}

static void Main()
{
Point p
= new Point();

p.x
= p.y = 1 ;
Console.WriteLine(p);
// 显示(1, 1)

p.Change(
2 , 2 );
Console.WriteLine(p);
// 显示(2, 2)

Object o
= p;
Console.WriteLine(o);
// 显示(2, 2)

((Point) o).Change(
3 , 3 ); // 在堆栈上改变拆箱后临时的Point对象
Console.WriteLine(o); // 显示(2, 2)

// 对p执行装箱,然后改变已装箱对象,最后丢弃
((IChangeBoxedPoint) p).Change( 4 , 4 );
Console.WriteLine(p);
// 显示(2, 2)

// 改变已装箱对象,并显示其内容
((IChangeBoxedPoint) o).Change( 5 , 5 );
Console.WriteLine(o);
// 显示(5, 5)
}

  这是一段比较有趣的代码,帮助我们加深对值类型装箱、拆箱的理解。

完全限定接口名技巧

  当一个类型需要实现多个接口,而碰巧它们的方法又有相同的名称和签名时,如何处理?

  示例代码:

   
     
public interface IWindow
{
object GetMenu();
}

public interface IRestaurant
{
object GetMenu();
}

public class Pizza : IWindow, IRestaurant
{
//完全限定接口名称
object IWindow.GetMenu(){......}
object IRestaurant.GetMenu(){......}

// 这个GetMenu方法与接口没有任何关系
public object GetMenu() {......}
}

  C#编译器在辨析接口成员实现时,会按照“先完全限定接口成员,后非完全限定接口成员”的顺序来进行辨析。

  注意,上面的完全限定接口方法没有被声明为public,不能这样做的原因是这些方法有着双重身份:它们有时为公有方法,有时又为私有方法。看下面的代码:

   
     
static void SomeMethod()
{
Pizza p
= new Pizza();

object menu;

// 调用公有的GetMenu方法,使用Pizza引用
// 完全限定接口方法将为私有方法,不能被调用
menu = p.GetMenu();

// 调用IWindow的GetMenu方法。使用IWindow引用
menu = ((IWindow) p).GetMenu();

// 调用IRestaurant的GetMenu方法,使用IRestaurant引用
menu = ((IRestaurant) p).GetMenu();
}

  当我们在一个类型中用完全限定接口名来定义一个接口方法时,该方法被认为是私有方法,不能使用类型本身的引用来调用它。但当我们将该类型的引用转型为一个接口时,该接口中定义的方法可被调用,这时它又成为一个公有方法。

  完全限定接口名这一技术被广泛用于FCL类库中。比如List<T>类型中实现ICollection接口的SyncRoot属性时就使用到了这一技巧。List<T>类型唯有转换为ICollection的引用才能获取SyncRoot属性。

你可能感兴趣的:(Microsoft)