Cross-Language Interoperability

Updated: May 2012

This section describes the common language runtime's built-in support for language interoperability and explains the role that the Common Language Specification (CLS) plays in enabling guaranteed cross-language interoperability.

Language interoperability is the ability of code to interact with code that is written by using a different programming language. Language interoperability can help maximize code reuse and improve the efficiency of the development process.

Because developers use a wide variety of tools and technologies, each of which might support different features and types, it has historically been difficult to ensure language interoperability. However, language compilers and tools that target the common language runtime benefit from the runtime's built-in support for language interoperability.

The common language runtime provides the necessary foundation for language interoperability by specifying and enforcing a common type system and by providing metadata. Because all languages targeting the runtime follow the common type system rules for defining and using types, the usage of types is consistent across languages. Metadata enables language interoperability by defining a uniform mechanism for storing and retrieving information about types. Compilers store type information as metadata, and the common language runtime uses this information to provide services during execution; the runtime can manage the execution of multilanguage applications because all type information is stored and retrieved in the same way, regardless of the language the code was written in.

Managed code benefits from the runtime's support for language interoperability in the following ways:

  • Types can inherit implementation from other types, pass objects to another type's methods, and call methods defined on other types, regardless of the language the types are implemented in.

  • Debuggers, profilers, or other tools are required to understand only one environment—the Microsoft intermediate language (MSIL) and metadata for the common language runtime—and they can support any programming language that targets the runtime.

  • Exception handling is consistent across languages. Your code can throw an exception in one language and that exception can be caught and understood by an object written in another language.

Even though the runtime provides all managed code with support for executing in a multilanguage environment, there is no guarantee that the functionality of the types you create can be fully used by the programming languages that other developers use. This is primarily because each language compiler targeting the runtime uses the type system and metadata to support its own unique set of language features. In cases where you do not know which language the calling code will be written in, you are unlikely to know whether the features your component exposes are accessible to the caller. For example, if your language of choice provides support for unsigned integers, you might design a method with a parameter of type UInt32. However; that method would be unusable from a language that has no notion of unsigned integers.

To ensure that your managed code is accessible to developers who are using other programming languages, the .NET Framework provides the Common Language Specification (CLS), which describes a fundamental set of language features and defines rules for how those features are used. For more information about CLS compliance in components and tools, see Writing CLS-Compliant Code.

A Practical Example

The following example illustrates cross-language interoperability by creating a class library named Utilities.dll that includes two classes, NumericLib and StringLib. The NumericLib class is written in C#, and the StringLib class is written in Visual Basic. The following is the source code for StringUtil.vb, which includes a single member, ToTitleCase, in its StringLib class.

Imports System.Collections.Generic
Imports System.Runtime.CompilerServices

Public Module StringLib
   Private exclusions As List(Of String) 

   Sub New()
      Dim words() As String = { "a", "an", "and", "of", "the" }
      exclusions = New List(Of String)
      exclusions.AddRange(words)
   End Sub

   <Extension()> _
   Public Function ToTitleCase(title As String) As String
      Dim words() As String = title.Split() 
      Dim result As String = String.Empty

      For ctr As Integer = 0 To words.Length - 1
         Dim word As String = words(ctr)
         If ctr = 0 OrElse Not exclusions.Contains(word.ToLower()) Then
            result += word.Substring(0, 1).ToUpper() + _
                      word.Substring(1).ToLower()
         Else
            result += word.ToLower()
         End If
         If ctr <= words.Length - 1 Then
            result += " "             
         End If   
      Next 
      Return result 
   End Function
End Module

The following is the source code for NumberUtil.cs, which defines a NumericLib class that has two members, IsEven and NearZero.

using System;

public static class NumericLib 
{
   public static bool IsEven(this IConvertible number)
   {
      if (number is Byte ||
          number is SByte ||
          number is Int16 ||
          number is UInt16 || 
          number is Int32 || 
          number is UInt32 ||
          number is Int64)
         return ((long) number) % 2 == 0;
      else if (number is UInt64)
         return ((ulong) number) %2 == 0;
      else
         throw new NotSupportedException("IsEven called for a non-integer value.");
   }

   public static bool NearZero(double number)
   {
      return number < .00001; 
   }
}

To package the two classes in a single assembly, you must compile them into modules. You compile the Visual Basic source code file into a module with the following command:

vbc /t:module StringUtil.vb 

For more information about the command-line syntax of the Visual Basic compiler, see Building from the Command Line (Visual Basic).

You compile the C# source code file into a module with the following command:

csc /t:module NumberUtil.cs

For more information about the command-line syntax of the C# compiler, see Command-line Building With csc.exe.

You then use the Link tool (Link.exe) to compile the two modules into an assembly:

link numberutil.netmodule stringutil.netmodule /out:UtilityLib.dll /dll 

The following example then calls the NumericLib.NearZero and StringLib.ToTitleCase methods. Note that both the Visual Basic code and the C# code are able to access the methods in both classes.

Module Example
   Public Sub Main()
      Dim dbl As Double = 0.0 - Double.Epsilon
      Console.WriteLine(NumericLib.NearZero(dbl))

      Dim s As String = "war and peace"
      Console.WriteLine(s.ToTitleCase())
   End Sub
End Module
' The example displays the following output:
'       True
'       War and Peace
using System;

public class Example
{
   public static void Main()
   {
      Double dbl = 0.0 - Double.Epsilon;
      Console.WriteLine(NumericLib.NearZero(dbl));

      string s = "war and peace";
      Console.WriteLine(s.ToTitleCase());
   }
}
// The example displays the following output:
//       True
//       War and Peace

The Visual Basic code can be compiled from the command line by using the following command:

vbc example.vb /r:UtilityLib.dll

To compile with C#, change the name of the compiler from vbc to csc, and change the file extension from .vb to .cs.

Title

Description

Common Language Specification

Explains the need for a set of features common to all languages and identifies CLS rules and features.

Writing CLS-Compliant Code

Discusses the meaning of CLS compliance for components and identifies levels of CLS compliance for tools.

Common Type System

Describes how types are declared, used, and managed by the common language runtime.

Metadata and Self-Describing Components

Explains the common language runtime's mechanism for describing a type and storing that information with the type itself.

Change History

Date

History

Reason

May 2012

Added an example.

Customer feedback.