Criar assemblies satélite para aplicativos .NET
Os arquivos de recursos desempenham um papel central em aplicativos localizados. Eles permitem que um aplicativo exiba cadeias de caracteres, imagens e outros dados no idioma e na cultura do usuário e fornecem dados alternativos se os recursos para o idioma ou a cultura do usuário não estiverem disponíveis. O .NET usa um modelo hub-and-spoke para localizar e recuperar recursos localizados. O hub é o assembly principal que contém o código executável não localizável e os recursos para uma única cultura, que é chamada de cultura neutra ou padrão. A cultura padrão é a cultura de fallback para o aplicativo; ele é usado quando não há recursos localizados disponíveis. Use o NeutralResourcesLanguageAttribute atributo para designar a cultura da cultura padrão do aplicativo. Cada spoke se conecta a um assembly satélite que contém os recursos para uma única cultura localizada, mas não contém nenhum código. Como os assemblies satélite não fazem parte do assembly principal, você pode facilmente atualizar ou substituir recursos que correspondem a uma cultura específica sem substituir o assembly principal para o aplicativo.
Nota
Os recursos da cultura padrão de um aplicativo também podem ser armazenados em um assembly satélite. Para fazer isso, atribua ao NeutralResourcesLanguageAttribute atributo um valor de UltimateResourceFallbackLocation.Satellite.
Nome e localização da montagem satélite
O modelo hub-and-spoke requer que você coloque recursos em locais específicos para que eles possam ser facilmente localizados e usados. Se você não compilar e nomear recursos conforme o esperado, ou se não colocá-los nos locais corretos, o Common Language Runtime não poderá localizá-los e usará os recursos da cultura padrão. O gerenciador de recursos .NET é representado pelo ResourceManager tipo e é usado para acessar automaticamente recursos localizados. O gestor de recursos requer o seguinte:
Um único conjunto de satélites deve incluir todos os recursos para uma determinada cultura. Em outras palavras, você deve compilar vários arquivos .txt ou .resx em um único arquivo binário .resources .
Deve haver um subdiretório separado no diretório do aplicativo para cada cultura localizada que armazena os recursos dessa cultura. O nome do subdiretório deve ser o mesmo que o nome da cultura. Como alternativa, você pode armazenar seus assemblies satélite no cache de assembly global. Neste caso, o componente de informação de cultura do nome forte da assembleia deve indicar sua cultura. Para obter mais informações, consulte Instalar assemblies satélite no Cache de Assembly Global.
Nota
Se seu aplicativo incluir recursos para subculturas, coloque cada subcultura em um subdiretório separado sob o diretório do aplicativo. Não coloque subculturas em subdiretórios sob o diretório da cultura principal.
O assembly satélite deve ter o mesmo nome que o aplicativo e deve usar a extensão de nome de arquivo ".resources.dll". Por exemplo, se um aplicativo for nomeado Example.exe, o nome de cada conjunto satélite deve ser Example.resources.dll. O nome do assembly satélite não indica a cultura de seus arquivos de recursos. No entanto, o assembly satélite aparece em um diretório que especifica a cultura.
Informações sobre a cultura do conjunto satélite devem ser incluídas nos metadados do conjunto. Para armazenar o nome da cultura nos metadados do assembly satélite, especifique a opção ao usar o
/culture
Assembly Linker para incorporar recursos no assembly satélite.
A ilustração a seguir mostra uma estrutura de diretório de exemplo e requisitos de local para aplicativos que você não está instalando no cache de assembly global. Os itens com extensões .txt e .resources não serão fornecidos com o aplicativo final. Estes são os arquivos de recursos intermediários usados para criar os assemblies finais de recursos de satélite. Neste exemplo, você pode substituir os arquivos .resx pelos arquivos .txt . Para obter mais informações, consulte Empacotar e implantar recursos.
A imagem a seguir mostra o diretório de montagem satélite:
Compilar montagens satélite
Use o Resource File Generator (resgen.exe) para compilar arquivos de texto ou arquivos XML (.resx) que contêm recursos para arquivos binários .resources. Em seguida, use o Assembly Linker (al.exe) para compilar arquivos .resources em assemblies satélite. al.exe cria um assembly a partir dos arquivos .resources especificados. Os conjuntos de satélites podem conter apenas recursos; eles não podem conter nenhum código executável.
O comando al.exe a seguir cria um assembly satélite para o aplicativo Example
a partir do arquivo de recursos alemão strings.de.resources.
al -target:lib -embed:strings.de.resources -culture:de -out:Example.resources.dll
O comando al.exe a seguir também cria um assembly satélite para o aplicativo Example
a partir do arquivo strings.de.resources. A opção /template faz com que o assembly satélite herde todos os metadados do assembly, exceto suas informações de cultura do assembly pai (Example.dll).
al -target:lib -embed:strings.de.resources -culture:de -out:Example.resources.dll -template:Example.dll
A tabela a seguir descreve as opções de al.exe usadas nesses comandos com mais detalhes:
Opção | Description |
---|---|
-target:lib |
Especifica que o assembly satélite é compilado em um arquivo de biblioteca (.dll). Como um assembly satélite não contém código executável e não é o assembly principal de um aplicativo, você deve salvar assemblies satélite como DLLs. |
-embed:strings.de.resources |
Especifica o nome do arquivo de recurso a ser incorporado quando al.exe compila o assembly. Você pode incorporar vários arquivos .resources em um assembly de satélite, mas se estiver seguindo o modelo hub-and-spoke, deverá compilar um assembly de satélite para cada cultura. No entanto, você pode criar arquivos .resources separados para cadeias de caracteres e objetos. |
-culture:de |
Especifica a cultura do recurso a ser compilado. O Common Language Runtime usa essas informações quando procura os recursos para uma cultura especificada. Se você omitir essa opção, al.exe ainda compilará o recurso, mas o tempo de execução não poderá encontrá-lo quando um usuário solicitá-lo. |
-out:Example.resources.dll |
Especifica o nome do arquivo de saída. O nome deve seguir o padrão de nomenclatura baseName.resources., onde baseName é o nome do assembly principal e extension é uma extensão de nome de arquivo válida (como .dll). O tempo de execução não é capaz de determinar a cultura de um assembly satélite com base em seu nome de arquivo de saída; você deve usar a opção /culture para especificá-lo. |
-template:Example.dll |
Especifica um assembly do qual o assembly satélite herdará todos os metadados do assembly, exceto o campo de cultura. Essa opção afeta os assemblies satélite somente se você especificar um assembly que tenha um nome forte. |
Para obter uma lista completa das opções disponíveis com al.exe, consulte Assembly Linker (al.exe).
Nota
Pode haver momentos em que você deseja usar a tarefa .NET Core MSBuild para compilar assemblies satélite, mesmo que você esteja visando o .NET Framework. Por exemplo, você pode querer usar a opção determinística do compilador C# para poder comparar assemblies de compilações diferentes. Nesse caso, defina GenerateSatelliteAssembliesForCore como no arquivo .csproj para gerar assemblies satélite usando csc.exe em vez de Al.exe (Assembly Linker).true
<Project>
<PropertyGroup>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
</PropertyGroup>
</Project>
A tarefa .NET Core MSBuild usa csc.exe em vez de al.exe para gerar assemblies satélite, por padrão. Para obter mais informações, consulte Facilitar a aceitação da geração de montagem de satélite "Core".
Exemplo de montagens de satélite
A seguir está um exemplo simples de "Hello world" que exibe uma caixa de mensagem contendo uma saudação localizada. O exemplo inclui recursos para as culturas inglesa (Estados Unidos), francesa (França) e russa (Rússia), e sua cultura de fallback é o inglês. Para criar o exemplo, faça o seguinte:
Crie um arquivo de recurso chamado Greeting.resx ou Greeting.txt para conter o recurso para a cultura padrão. Armazene uma única cadeia de caracteres chamada
HelloString
cujo valor é "Hello world!" neste arquivo.Para indicar que o inglês (en) é a cultura padrão do aplicativo, adicione o seguinte System.Resources.NeutralResourcesLanguageAttribute atributo ao arquivo AssemblyInfo do aplicativo ou ao arquivo de código-fonte principal que será compilado no assembly principal do aplicativo.
[assembly: NeutralResourcesLanguage("en")]
<Assembly: NeutralResourcesLanguage("en")>
Adicione suporte para culturas adicionais (
en-US
,fr-FR
eru-RU
) ao aplicativo da seguinte maneira:Para dar suporte à cultura inglesa (Estados Unidos), crie um arquivo de recurso chamado Greeting.en-US.resx ou Greeting.en-US.txt e armazene nele uma única cadeia de caracteres cujo
HelloString
valor é "Oi worlden-US
!".Para dar suporte à cultura francesa (França), crie um arquivo de recurso chamado Greeting.fr-FR.resx ou Greeting.fr-FR.txt e armazene nele uma única cadeia de caracteres cujo
HelloString
valor é "Salut tout lefr-FR
monde!".Para dar suporte
ru-RU
à cultura russa (Rússia), crie um arquivo de recurso chamado Greeting.ru-RU.resx ou Greeting.ru-RU.txt e armazene nele uma única cadeia de caracteres cujoHelloString
valor é "Всем привет!".
Use resgen.exe para compilar cada texto ou arquivo de recurso XML para um arquivo .resources binário. A saída é um conjunto de arquivos que têm o mesmo nome de arquivo raiz que os arquivos .resx ou .txt , mas uma extensão .resources . Se você criar o exemplo com o Visual Studio, o processo de compilação será tratado automaticamente. Se você não estiver usando o Visual Studio, execute os seguintes comandos para compilar os arquivos .resx em arquivos .resources :
resgen Greeting.resx resgen Greeting.en-us.resx resgen Greeting.fr-FR.resx resgen Greeting.ru-RU.resx
Se seus recursos estiverem em arquivos de texto em vez de arquivos XML, substitua a extensão .resx por .txt.
Compile o seguinte código-fonte junto com os recursos para a cultura padrão no assembly principal do aplicativo:
Importante
Se você estiver usando a linha de comando em vez de Visual Studio para criar o exemplo, você deve modificar a chamada para o ResourceManager construtor de classe para o seguinte:
ResourceManager rm = new ResourceManager("Greeting", typeof(Example).Assembly);
using System; using System.Globalization; using System.Reflection; using System.Resources; using System.Threading; using System.Windows.Forms; class Example { static void Main() { // Create array of supported cultures string[] cultures = {"en-CA", "en-US", "fr-FR", "ru-RU"}; Random rnd = new Random(); int cultureNdx = rnd.Next(0, cultures.Length); CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; try { CultureInfo newCulture = new CultureInfo(cultures[cultureNdx]); Thread.CurrentThread.CurrentCulture = newCulture; Thread.CurrentThread.CurrentUICulture = newCulture; ResourceManager rm = new ResourceManager("Example.Greeting", typeof(Example).Assembly); string greeting = String.Format("The current culture is {0}.\n{1}", Thread.CurrentThread.CurrentUICulture.Name, rm.GetString("HelloString")); MessageBox.Show(greeting); } catch (CultureNotFoundException e) { Console.WriteLine("Unable to instantiate culture {0}", e.InvalidCultureName); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; Thread.CurrentThread.CurrentUICulture = originalCulture; } } }
Imports System.Globalization Imports System.Resources Imports System.Threading Module Module1 Sub Main() ' Create array of supported cultures Dim cultures() As String = {"en-CA", "en-US", "fr-FR", "ru-RU"} Dim rnd As New Random() Dim cultureNdx As Integer = rnd.Next(0, cultures.Length) Dim originalCulture As CultureInfo = Thread.CurrentThread.CurrentCulture Try Dim newCulture As New CultureInfo(cultures(cultureNdx)) Thread.CurrentThread.CurrentCulture = newCulture Thread.CurrentThread.CurrentUICulture = newCulture Dim greeting As String = String.Format("The current culture is {0}.{1}{2}", Thread.CurrentThread.CurrentUICulture.Name, vbCrLf, My.Resources.Greetings.HelloString) MsgBox(greeting) Catch e As CultureNotFoundException Console.WriteLine("Unable to instantiate culture {0}", e.InvalidCultureName) Finally Thread.CurrentThread.CurrentCulture = originalCulture Thread.CurrentThread.CurrentUICulture = originalCulture End Try End Sub End Module
Se o aplicativo for chamado Exemplo e você estiver compilando a partir da linha de comando, o comando para o compilador C# é:
csc Example.cs -res:Greeting.resources
O comando correspondente do compilador do Visual Basic é:
vbc Example.vb -res:Greeting.resources
Crie um subdiretório no diretório principal do aplicativo para cada cultura localizada suportada pelo aplicativo. Você deve criar um subdiretório en-US, fr-FR e ru-RU. O Visual Studio cria esses subdiretórios automaticamente como parte do processo de compilação.
Incorpore os arquivos .resources específicos da cultura individual em assemblies satélite e salve-os no diretório apropriado. O comando para fazer isso para cada arquivo .resources é:
al -target:lib -embed:Greeting.culture.resources -culture:culture -out:culture\Example.resources.dll
onde cultura é o nome da cultura cujos recursos a montagem satélite contém. Visual Studio lida com esse processo automaticamente.
Em seguida, você pode executar o exemplo. Ele fará aleatoriamente uma das culturas suportadas a cultura atual e exibirá uma saudação localizada.
Instalar assemblies satélite no Cache de Assembly Global
Em vez de instalar assemblies em um subdiretório de aplicativo local, você pode instalá-los no cache de assembly global. Isso é particularmente útil se você tiver bibliotecas de classes e assemblies de recursos de biblioteca de classes que são usados por vários aplicativos.
A instalação de assemblies no cache de assembly global requer que eles tenham nomes fortes. Os assemblies de nome forte são assinados com um par de chaves pública/privada válido. Eles contêm informações de versão que o tempo de execução usa para determinar qual assembly usar para satisfazer uma solicitação de vinculação. Para obter mais informações sobre nomes fortes e controle de versão, consulte Controle de versão de assembly. Para obter mais informações sobre nomes fortes, consulte Assemblies com nomes fortes.
Quando você está desenvolvendo um aplicativo, é improvável que você tenha acesso ao par final de chaves pública/privada. Para instalar um assembly satélite no cache de assembly global e garantir que ele funcione conforme o esperado, você pode usar uma técnica chamada assinatura atrasada. Quando você atrasa a assinatura de um assembly, no momento da compilação você reserva espaço no arquivo para a assinatura de nome forte. A assinatura real é adiada para mais tarde, quando o par final de chaves pública/privada estiver disponível. Para obter mais informações sobre assinatura atrasada, consulte Atrasar a assinatura de um assembly.
Obter a chave pública
Para atrasar a assinatura de um assembly, você deve ter acesso à chave pública. Você pode obter a chave pública real da organização em sua empresa que fará a eventual assinatura ou criar uma chave pública usando a ferramenta Nome forte (sn.exe).
O comando Sn.exe a seguir cria um par de chaves pública/privada de teste. A opção –k especifica que Sn.exe deve criar um novo par de chaves e salvá-lo em um arquivo chamado TestKeyPair.snk.
sn –k TestKeyPair.snk
Você pode extrair a chave pública do arquivo que contém o par de chaves de teste. O comando a seguir extrai a chave pública de TestKeyPair.snk e a salva em PublicKey.snk:
sn –p TestKeyPair.snk PublicKey.snk
Atrasar a assinatura de uma Assembleia
Depois de obter ou criar a chave pública, use o Assembly Linker (al.exe) para compilar o assembly e especificar a assinatura atrasada.
O comando al.exe a seguir cria um assembly satélite de nome forte para o aplicativo StringLibrary a partir do arquivo strings.ja.resources:
al -target:lib -embed:strings.ja.resources -culture:ja -out:StringLibrary.resources.dll -delay+ -keyfile:PublicKey.snk
A opção -delay+ especifica que o Assembly Linker deve atrasar a assinatura do assembly. A opção -keyfile especifica o nome do arquivo de chave que contém a chave pública a ser usada para atrasar a assinatura do assembly.
Voltar a assinar uma Assembleia
Antes de implantar seu aplicativo, você deve assinar novamente o assembly satélite assinado com atraso com o par de chaves real. Você pode fazer isso usando Sn.exe.
O seguinte comando Sn.exe assina StringLibrary.resources.dll com o par de chaves armazenado no arquivo RealKeyPair.snk. A opção –R especifica que um assembly assinado anteriormente ou assinado com atraso deve ser assinado novamente.
sn –R StringLibrary.resources.dll RealKeyPair.snk
Instalar um assembly satélite no cache de assembly global
Quando o tempo de execução procura recursos no processo de fallback de recursos, ele procura primeiro no cache de assembly global. (Para obter mais informações, consulte a seção "Processo de fallback de recursos" de Empacote e implante recursos.) Assim que um assembly satélite é assinado com um nome forte, ele pode ser instalado no cache de assembly global usando a ferramenta Global Assembly Cache (gacutil.exe).
O seguinte comando Gacutil.exe instala StringLibrary.resources.dll* no cache de assembly global:
gacutil -i:StringLibrary.resources.dll
A opção /i especifica que Gacutil.exe deve instalar o assembly especificado no cache de assembly global. Depois que o assembly satélite é instalado no cache, os recursos que ele contém ficam disponíveis para todos os aplicativos projetados para usar o assembly satélite.
Recursos no cache de assembly global: um exemplo
O exemplo a seguir usa um método em uma biblioteca de classes .NET para extrair e retornar uma saudação localizada de um arquivo de recurso. A biblioteca e seus recursos são registrados no cache de assembly global. O exemplo inclui recursos para as culturas inglesa (Estados Unidos), francesa (França), russa (Rússia) e inglesa. O inglês é a cultura padrão; seus recursos são armazenados na assembléia principal. O exemplo inicialmente atrasa a assinatura da biblioteca e seus assemblies satélite com uma chave pública e, em seguida, assina-os novamente com um par de chaves pública/privada. Para criar o exemplo, faça o seguinte:
Se você não estiver usando o Visual Studio, use o seguinte comando Strong Name Tool (Sn.exe) para criar um par de chaves públicas/privadas chamado ResKey.snk:
sn –k ResKey.snk
Se você estiver usando o Visual Studio, use a guia Assinatura da caixa de diálogo Propriedades do projeto para gerar o arquivo de chave.
Use o seguinte comando Strong Name Tool (Sn.exe) para criar um arquivo de chave pública chamado PublicKey.snk:
sn –p ResKey.snk PublicKey.snk
Crie um arquivo de recurso chamado Strings.resx para conter o recurso para a cultura padrão. Armazene uma única cadeia de caracteres chamada
Greeting
cujo valor é "Como você faz?" nesse arquivo.Para indicar que "en" é a cultura padrão do aplicativo, adicione o seguinte System.Resources.NeutralResourcesLanguageAttribute atributo ao arquivo AssemblyInfo do aplicativo ou ao arquivo de código-fonte principal que será compilado no assembly principal do aplicativo:
[assembly:NeutralResourcesLanguageAttribute("en")]
<Assembly: NeutralResourcesLanguageAttribute("en")>
Adicione suporte para culturas adicionais (as culturas en-US, fr-FR e ru-RU) ao aplicativo da seguinte maneira:
Para suportar a cultura "en-US" ou Inglês (Estados Unidos), crie um arquivo de recurso chamado Strings.en-US.resx ou Strings.en-US.txt e armazene nele uma única cadeia de caracteres cujo
Greeting
valor é "Olá!".Para suportar a cultura "fr-FR" ou francesa (França), crie um arquivo de recurso chamado Strings.fr-FR.resx ou Strings.fr-FR.txt e armazene nele uma única cadeia de caracteres cujo
Greeting
valor é "Bon jour!".Para suportar a cultura "ru-RU" ou russo (Rússia), crie um arquivo de recurso chamado Strings.ru-RU.resx ou Strings.ru-RU.txt e armazene nele uma única cadeia de caracteres cujo
Greeting
valor é "Привет!".
Use resgen.exe para compilar cada texto ou arquivo de recurso XML para um arquivo .resources binário. A saída é um conjunto de arquivos que têm o mesmo nome de arquivo raiz que os arquivos .resx ou .txt , mas uma extensão .resources . Se você criar o exemplo com o Visual Studio, o processo de compilação será tratado automaticamente. Se você não estiver usando o Visual Studio, execute o seguinte comando para compilar os arquivos .resx em arquivos .resources :
resgen filename
Onde filename é o caminho opcional, o nome do arquivo e a extensão do arquivo .resx ou de texto.
Compile o seguinte código-fonte para StringLibrary.vb ou StringLibrary.cs juntamente com os recursos para a cultura padrão em um assembly de biblioteca assinado com atraso chamado StringLibrary.dll:
Importante
Se você estiver usando a linha de comando em vez de Visual Studio para criar o exemplo, você deve modificar a chamada para o ResourceManager construtor de classe para
ResourceManager rm = new ResourceManager("Strings",
typeof(Example).Assembly);
.using System; using System.Globalization; using System.Reflection; using System.Resources; using System.Threading; [assembly:NeutralResourcesLanguageAttribute("en")] public class StringLibrary { public string GetGreeting() { ResourceManager rm = new ResourceManager("Strings", Assembly.GetAssembly(typeof(StringLibrary))); string greeting = rm.GetString("Greeting"); return greeting; } }
Imports System.Globalization Imports System.Reflection Imports System.Resources Imports System.Threading <Assembly: NeutralResourcesLanguageAttribute("en")> Public Class StringLibrary Public Function GetGreeting() As String Dim rm As New ResourceManager("Strings", _ Assembly.GetAssembly(GetType(StringLibrary))) Dim greeting As String = rm.GetString("Greeting") Return greeting End Function End Class
O comando para o compilador C# é:
csc -t:library -resource:Strings.resources -delaysign+ -keyfile:publickey.snk StringLibrary.cs
O comando correspondente do compilador do Visual Basic é:
vbc -t:library -resource:Strings.resources -delaysign+ -keyfile:publickey.snk StringLibrary.vb
Crie um subdiretório no diretório principal do aplicativo para cada cultura localizada suportada pelo aplicativo. Você deve criar um subdiretório en-US, fr-FR e ru-RU. O Visual Studio cria esses subdiretórios automaticamente como parte do processo de compilação. Como todos os assemblies satélite têm o mesmo nome de arquivo, os subdiretórios são usados para armazenar assemblies satélites específicos de cultura individual até que sejam assinados com um par de chaves pública/privada.
Incorpore os arquivos .resources específicos da cultura individual em assemblies satélite assinados com atraso e salve-os no diretório apropriado. O comando para fazer isso para cada arquivo .resources é:
al -target:lib -embed:Strings.culture.resources -culture:culture -out:culture\StringLibrary.resources.dll -delay+ -keyfile:publickey.snk
onde cultura é o nome de uma cultura. Neste exemplo, os nomes de cultura são en-US, fr-FR e ru-RU.
Assine novamente StringLibrary.dll usando a ferramenta Nome forte (sn.exe) da seguinte maneira:
sn –R StringLibrary.dll RealKeyPair.snk
Assine novamente os conjuntos de satélites individuais. Para fazer isso, use a ferramenta Nome forte (sn.exe) da seguinte maneira para cada conjunto de satélite:
sn –R StringLibrary.resources.dll RealKeyPair.snk
Registre StringLibrary.dll e cada um de seus assemblies satélite no cache de assembly global usando o seguinte comando:
gacutil -i filename
onde filename é o nome do arquivo a ser registrado.
Se você estiver usando o Visual Studio, crie um novo projeto de Aplicativo de Console chamado
Example
, adicione uma referência a StringLibrary.dll e o seguinte código-fonte a ele e compile.using System; using System.Globalization; using System.Threading; public class Example { public static void Main() { string[] cultureNames = { "en-GB", "en-US", "fr-FR", "ru-RU" }; Random rnd = new Random(); string cultureName = cultureNames[rnd.Next(0, cultureNames.Length)]; Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName); Console.WriteLine("The current UI culture is {0}", Thread.CurrentThread.CurrentUICulture.Name); StringLibrary strLib = new StringLibrary(); string greeting = strLib.GetGreeting(); Console.WriteLine(greeting); } }
Imports System.Globalization Imports System.Threading Module Example Public Sub Main() Dim cultureNames() As String = {"en-GB", "en-US", "fr-FR", "ru-RU"} Dim rnd As New Random() Dim cultureName As String = cultureNames(rnd.Next(0, cultureNames.Length)) Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName) Console.WriteLine("The current UI culture is {0}", Thread.CurrentThread.CurrentUICulture.Name) Dim strLib As New StringLibrary() Dim greeting As String = strLib.GetGreeting() Console.WriteLine(greeting) End Sub End Module
Para compilar a partir da linha de comando, use o seguinte comando para o compilador C#:
csc Example.cs -r:StringLibrary.dll
A linha de comando para o compilador do Visual Basic é:
vbc Example.vb -r:StringLibrary.dll
Execute Example.exe.