Writing CLS-Compliant Code

Common Language Specification (CLS) compliance generally refers to the claim that CLS rules and restrictions are being followed. However, the concept has a more specific meaning depending on whether you are describing CLS-compliant code or CLS-compliant development tools, such as a compiler. CLS-compliant tools can help you write CLS-compliant code.

CLS-Compliant Code

If you want your code to be CLS-compliant, you must expose functionality in a way that is CLS-compliant in the following places:

  • Definitions of your public classes.

  • Definitions of the public members of public classes, and of members accessible to derived classes (family access).

  • Parameters and return types of public methods of public classes, and of methods accessible to derived classes.

The features you use in the definitions of your private classes, in the definitions of private methods on public classes, and in local variables do not have to follow the CLS rules. You can also use any language features you want in the code that implements your class and still have a CLS-compliant component.

Note

Jagged arrays — that is, arrays of arrays — are CLS-compliant. In the .NET Framework version 1.0, the C# compiler mistakenly reports that they are not.

You can mark assemblies, modules, types, and members as either CLS-compliant or not CLS compliant using the CLSCompliantAttribute. All assemblies that are intended to be CLS-compliant should be marked as such. An assembly that is not marked as CLS-compliant is considered to be not CLS compliant. If no CLS attribute is applied to a type, that type is assumed to have the same CLS compliance as the assembly in which the type is defined. Similarly, if no CLS attribute is applied to a member, the member is considered to have the same CLS compliance as the type that defines it. You cannot mark a program element as CLS-compliant if its enclosing element is not marked as CLS-compliant. The example at the end of this topic illustrates the use of the CLSCompliantAttribute.

Assemblies, modules, and types can be CLS-compliant even if some parts of the assembly, module, or type are not CLS-compliant, as long as two conditions are met:

  • If the element is marked as CLS-compliant, the parts that are not CLS-compliant must be marked using the CLSCompliantAttribute with its argument set to false.

  • A comparable CLS-compliant alternative member must be supplied for each member that is not CLS-compliant.

If you design a CLS–compliant class library, your library will have a guarantee of interoperability with a wide range of programming languages; therefore, your library is likely to have a wider customer base than a version that is not CLS-compliant.

The .NET Framework provides a CLS-compliant class library. For more information about this class library, see .NET Framework Class Library.

CLS-Compliant Tools

Languages that target the runtime have agreed to support CLS features and follow the CLS rules directed to compilers. These language compilers simplify CLS compliance by making the CLS data types and features available for creating components. The levels of CLS compliance among compilers and other tools are described as follows:

  • CLS-compliant consumer tools.

    Consumer tools are languages that enable developers to access all the features supplied by CLS-compliant libraries. Developers using these languages might not be able to extend CLS-compliant libraries by creating new types, but they can use any type defined by a compliant library. This level of compliance can be useful when you want to access a .NET Framework class library, but do not need to author new objects for consumption by others, such as when you are using Web Forms on an ASP.NET page or creating a Windows Forms user interface.

  • CLS-compliant extender tools.

    Extender tools are languages that allow developers to both use and extend types defined in CLS-compliant libraries. Developers can use existing types as well as define new types. Extender tools must follow all the rules that consumer tools must follow, as well as some additional rules, which are described in the specification for the Common Language Infrastructure, Partition I - Architecture, available from the Microsoft Developer Network (MSDN) Web site.

When you design your own CLS-compliant components, it is helpful to use a CLS-compliant tool. Writing CLS-compliant components without this support is more difficult because otherwise you might not have access to all the CLS features you want to use.

Some CLS-compliant language compilers, such as the C# or Visual Basic compilers, enable you to specify that you intend your code to be CLS-compliant. These compilers can check for CLS compliance and let you know when your code uses functionality that is not supported by the CLS. The C# and Visual Basic compilers allow you to mark a program element as CLS-compliant, which will cause the compiler to generate a compile-time error if the code is not CLS-compliant. For example, the following code generates a compiler warning.

<Assembly: CLSCompliant(True)>

<CLSCompliant(True)> Public Class MyCompliantClass
   Public Sub ChangeValue(value As UInt32)
   End Sub

   Public Shared Sub Main()
      Dim i As Integer = 2
      Console.WriteLine(i)
   End Sub   
End Class
using System;

// Assembly marked as compliant.
[assembly: CLSCompliant(true)]

// Class marked as compliant.
[CLSCompliant(true)]
public class MyCompliantClass {
   // ChangeValue exposes UInt32, which is not in CLS.
   // A compile-time warning results.
   public void ChangeValue(UInt32 value){ }

   public static void Main( ) {
   int i = 2;
   Console.WriteLine(i);
   }
}

This code generates the following C# warning:

warning CS3001: Argument type 'uint' is not CLS-compliant

or the following Visual Basic warning:

warning BC40028: Type of parameter 'value' is not CLS-compliant.

To remove the warning, you can indicate that ChangeValue is not compliant, as shown in the following example.

' Assembly marked as compliant.
<Assembly: CLSCompliant(True)>

' Class marked as compliant.
<CLSCompliant(True)> Public Class MyCompliantClass
   ' Method marked as not compliant.
   <CLSCompliant(False)> Public Sub ChangeValue(value As UInt32)
   End Sub

   Public Shared Sub Main()
      Dim i As Integer = 2
      Console.WriteLine(i)
   End Sub   
End Class
using System;

// Assembly marked as compliant.
[assembly: CLSCompliantAttribute(true)]

// Class marked as compliant.
[CLSCompliantAttribute(true)]
public class MyCompliantClass {
   // Method marked as not compliant.
   [CLSCompliantAttribute(false)]
   public void ChangeValue(UInt32 value){ }

   public static void Main( ) {
   int i = 2;
   Console.WriteLine(i);
   }
}

This code produces no compiler warnings. The output is 2.

For more information about how to specify the CLS-compliance of your code, see the documentation for the language compiler you are using.

See Also

Other Resources

Cross-Language Interoperability