CLR_via_C#.3rd 翻译[1.8 通用语言规范]

1.8 The Common Language Specification 通用语言规范

 

COM允许不同语言创建的对象能够进行相互之间的访问。另一方面,CLR现在集成了所有语言,并且允许一种语言创建的对象在另一个不同语言编写的代码中被看做同等的成员。CLR的标准类型集合、元数据、和通用执行环境使得这种集成成为可能。

 

语言集成是一个很遥远的目标,因为有一件事情是不容忽视的,编程语言之间有很大的区别。比如说,一些语言不区分大小写符号,有些不提供无符号整数,有些不支持操作符重载,有些方法不支持可变数目的参数。

 

如果你希望你创建的类型可以被其他编程语言方便的访问,只能使用编程语言中那些对其他语言来说也可用的特性。为了解决这一问题,微软定义了一个通用语言规范(Common Language Specification简称CLS)该规范为编译器厂商详细描述了面向CLR的编译器必须支持的一个最小特性集合。

 

CLR/CTS支持的功能比CLS定义的自己多的多,如果你不关心语言之间的可操作性,你可以开发一套功能非常丰富的类型,它们仅受你算用的那种语言的功能集的限制。具体的说,在开发类型和方法的时候,如果希望它们对外“可见”,能够从符合CLS的任何一种编程语言中访问,就必须遵守由CLS定义的规则。注意,假如代码只是从定义程序集的内部访问,CLS规则就不适用了。图1-6形象地演示了这一段想要表达的意思。

 

 

如图1-6 所示,CLR/CTS提供了一个功能集。有的语言公开了CLR/CTS的一个较大的子集。加入开发人员使用IL语言来编写程序,就可以使用CLR/CTS提供的全部功能。但是其他大所属语言,比如C#VB以及Fortran,只暴露了CLR/CTS功能的一个子集给开发人员。CLS 是所有语言都必须支持一个最小的子集。

 

如果你在用一种语言设计一种类型的时候,而且希望在另一种语言中使用该类型。那你就不该使用在CLS之外的任何功能。否则,其他开发人员使用其他语言写代码的时候,就可能无法访问这个类型的成员。

 

在下面的代码中,我们用C#定义了一个符合CLS的类型。然而,类型中含有几个不符合CLS的构造,造成C#编译器报错:

using System;

// Tell compiler to check for CLS compliance

[assembly: CLSCompliant(true)]

namespace SomeLibrary {

    // Warnings appear because the class is public

    public sealed class SomeLibraryType {

        // Warning: Return type of 'SomeLibrary.SomeLibraryType.Abc()'

        // is not CLS-compliant

        public UInt32 Abc() { return 0; }

        // Warning: Identifier 'SomeLibrary.SomeLibraryType.abc()'

        // differing only in case is not CLS-compliant

        public void abc() { }

        // No warning: this method is private

        private UInt32 ABC() { return 0; }
    
    }

}

在这段代码中,程序集中使用了【assemblyCLSCompliant(true)】特性(attribute)。这个特性告诉比那一起检查public 类型,判断是否存在任何不合适的构造,组织了从其他编程语言中访问该类型。上述代码编译时,C#编译器会报告两条警告消息。第一条警告是因为Abc方法返回了一个无符号的整型;一些语言是不能操作无符号整型的。第二个警告是因为该类型公开了两个public方法,这两个方法(Abcabc)只是大小写和返回值有区别。SB和其他一些语言无法区别这两个方法。

 

有趣的是,如果你删除“sealed class SomeLibraryType”之前的public 再重新编译,两个警告都会小时,这样一来,SomeLibraryType类型将默认为internal(而不是public),将不再想程序集的外部公开。要获得完整的CLS规则列表,青参见.NET框架SDK文档的跨语言互操作性一节(http://msdn.microsoft.com/en-us/library/730f1wy3.aspx )。

 

让我们来简化一下CLS的规则。在CLR中,一个类型的每个成员不是字段(数据)就是方法(行为)。这意味着每个编程语言都要能够访问数据和调用方法。确定的字段和方法通过特殊或者通用的方式来使用。为了简化编程,语言通常提供了额外的抽象,对这些常见的编程模式进行简化。例如,语言会公开每局、数组、属性、索引、委托、事件、构造器、析构器、操作符重载、转换操作符等概念。编译器在源代码中遇到上述任何一种构造,必须将其转换成字段和方法,使CLR和其他任何编程语言能够访问这些构造。

 

在一下类型定义中,包含一个构造器、一个析构器、一些重载的操作符、一个属性、一个索引器以及一个事件。注意,这些代码的目的只是让代码能够编译,并不代表实现一个类型的正确方式。

namespace EmitExamples.CLRviaC_
{
    internal sealed class Test
    {
        // Constructor
        public Test() { }
        // Finalizer
        ~Test() { }
        // Operator overload
        public static Boolean operator ==(Test t1, Test t2)
        {
            return true;
        }
        public static Boolean operator !=(Test t1, Test t2)
        {
            return false;
        }
        // An operator overload
        public static Test operator +(Test t1, Test t2) { return null; }
        // A property
        public String AProperty
        {
            get { return null; }
            set { }
        }
        // An indexer
        public String this[Int32 x]
        {
            get { return null; }
            set { }
        }
        // An event
        public event EventHandler AnEvent;
    }
}

 

当编译器编译这段代码的时候会得到一个类型,其中含有大量字段和方法。可以使用.NET框架SDK配套的IL反编译工具(ILDasm.exe)来检查最终生成的托管模块,(我在这里使用的另一个强大的反编译软件reflector.exe)如图1-7

 

 

如表1-4 解释了编程语言构造是如何映射到CLR字段/方法

 

 

Test类型还有另一些节点未在表1-4中列出,其中包括.CLASS.customAnEventAProperty以及Item——它们标识了与类型有关的其他元数据。这些节点不映射到字段或方法;它们只是提供了有关类型的一些额外的信息,供CLR、编程语言或者工具访问。例如,利用Reflector工具,可以发现Test 类型提供了一个名为AnEvent的时间,该事件通过两个方法(add_AnEvent 和 remove_AnEvent)公开。

原文地址:https://www.cnblogs.com/TivonStone/p/1812805.html