代码改变世界

Effective C# 学习笔记(四十九)创建符合CLS标准的程序集

2011-08-20 22:38  小郝(Kaibo Hao)  阅读(598)  评论(0编辑  收藏  举报

符合CLS(Common Language Subsystem)标准的程序集可以被其他跑在CLR的语言公用,这是.NET的一个引以为傲的特性,这样你用一种语言编写的程序集就可以被其他在CLR同样支持的程序调用了。要实现这个效果,要求更多的时间来设计构建你的程序集。主要要求两点:

  1. 所有publicprotected的成员方法的参数和返回值必须是符合CLS标准的。你只需在你的程序集属性上添加如下属性声明即可:

[assembly: System.CLSCompliant(true)]

这样声明后,你的程序集在编译时就会检查你里边的代码是否是符合CLS标准的。例如下面的两段代码由于UInt32类型并不支持CLS标准,就会在编译时报错。

// Not CLS Compliant, returns unsigned int:

public UInt32 Foo()

{

return foo;

}

// Not CLS compliant, parameter is an unsigned int.

public void Foo2(UInt32 parm)

{

}

 

  1. 所有那些不符合CLS标准的publicprotected成员方法,都应有符合CLS标准的方法来代替。

如并非所有的语言都支持的运算符重载,你就需要在代码中添加该运算符相等处理逻辑的静态方法,如下代码所示:

 

// Overloaded Addition operator, preferred C# syntax:

public static Foo operator +(Foo left, Foo right)

{

// Use the same implementation as the Add method:

return Foo.Add(left, right);//使用了静态方法中的逻辑,这样便于维护

}

// Static function, desirable for some languages:

public static Foo Add(Foo left, Foo right)

{

return new Foo(left.Bar + right.Bar);

}

 

注意:在继承时对于CLS标准的影响,下面的代码中的BasEventArgs类继承自符合CLS标准的类型EventArgs,但其内部有一个公有属性ErrorCode,其类型为 UInt32,不被CLS标准支持,所以当使用该类型(BadEventArgs)来做参数的方法或委托就不是符合CLS标准的了,如下代码所示:

public class BadEventArgs : EventArgs

{

public UInt32 ErrorCode;

}

 

// Hiding the non-compliant event argument:

public delegate void MyEventHandler(object sender, EventArgs args );

 

public event MyEventHandler OnStuffHappens;

 

// Code to raise Event:

BadEventArgs arg = new BadEventArgs();

arg.ErrorCode = 24;

 

// Interface is legal, runtime type is not:

OnStuffHappens(this, arg);//这里在编译时不出错,但在运行时就不符合CLS标准规范了

 

再来看一个例子:

public interface IFoo2

{

// Non-CLS compliant, Unsigned int

void DoStuff(UInt32 arg1, string arg2);//不符合CLS规范的方法

}

public class MyClass2 : IFoo2

{

// explicit interface implementation.

// DoStuff() is not part of MyClass's public interface

void IFoo2.DoStuff(UInt32 arg1, string arg2)

{

// content elided.

}

}

上面的代码定义了一个不符合CLS标准的方法IFoo2,其方法DoStuff(UInt32 arg1, string arg2)由于参数类型的原因,不符合规范。而MyClass2继承自该接口,并显示的实现了该方法。但对于MyClass2来说其还是符合CLS规范的,因为DoStuff方法的调用,是属于IFoo2的。也就是说在使用该类型的对象的DoStuff方法时,你需要先把该对象显示的转换为IFoo2的对象才能使用。也就是你只能这么调用DoStuff方法:

MyClass2 myClass2 = new MyClass2();

(myClass2 as IFoo2).DoStuff(1, "hello compliance");

 

总结:实现CLS标准的程序集可以被其他运行在CLR平台的语言调用,但是要付出一点设计和构建的努力。当然,也不是说你所有的程序集都要为了这个目标去构建,你只需在需要多语言交互的接口使用符合CLS标准来构建就可以了,把转换封装到接口中,这样产出比还是很可以接受的。 :)