Introducción:
En Visual Basic 9.0 (la versión que se incluye con Visual Studio Orcas o
que usa el .NET Framework 3.5, como prefieras), permite el uso de lo que se
conoce como ensamblados amigos, aunque Visual Basic 2005 nos permite crear
ensamblados amigos para usarlos tanto desde C# 2.0 o superior o desde Visual
Basic 9.0 (Orcas).
El acceso a los ensamblados amigos nos permite poder indicar en un ensamblado
que otros ensamblados pueden acceder a los elementos declarados como "amigos",
en Visual Basic se definen con Friend y en C# con internal.
Como sabes, todos los miembros declarados con Friend/internal solo son
visibles y por tanto accesibles desde el mismo ensamblado, si quisieras usar
cualquiera de esos elementos "amigos" desde otro ensamblado diferente, no
podrías, ya que para ese otro ensamblado externo, no son visibles.
En C# 2.0 (Visual C# 2005) se pueden definir y usar ese tipo de ensamblados.
Incluso con Visual Basic 2005 también se pueden definir los ensamblados amigos,
pero no se pueden usar.
Por tanto, un ensamblado "amigable" se puede definir tanto en Visual Basic
2005 como en C# 3.0, pero para usarlo solo podemos usar C#.
Al menos hasta la versión 2005 de Visual Studio, ya que la próxima versión de
Visual Studio Orcas si permite que Visual Basic sea un "consumidor" de
ensamblados amigos.
No voy a entrar en la "ética" de si eso es... conveniente o no... de esto te
hablo en Los ensamblados amigos o la ética al alcance de los programadores.
Aquí solo te voy a explicar cómo definir ese tipo de ensamblado amigo y cómo
usarlo.
Definir un ensamblado amigo
Imagina que tienes una librería de clases (o cualquier otro tipo de proyecto)
en el que defines ciertas clases como Friend (internal en C#), e incluso algunas
clases que son públicas en las que defines algunos métodos o propiedades como
"amigas".
Pues bien, esos "elementos" definidos como Friend/internal solo los podrás
acceder desde el mismo ensamblado en el que los has definido. Pero desde otro
ensamblado no podrás, ya que al ser "internos", no son visibles de forma
pública.
Ahora imagina que te planteas lo siguiente: Esos miembros o clases "internas"
las quiero usar desde otro ensamblado (ya sea DLL o EXE).
Aquí es donde entra en juego los ensamblados amigos.
Ahora (con las versiones de Visual Studio 2005 o .NET Framework 2.0), puedes
indicar que esas clases se usen desde otros ensamblados.
Para hacerlo, tendrás que añadir un atributo del tipo InternalsVisibleTo al
ensamblado que define los miembros "amigos". Esa clase está definida en el
espacio de nombres System.Runtime.CompilerServices y se debe aplicar a nivel del
ensamblado completo, por tanto, el mejor sitio para ponerlo es en el fichero
AssemblyInfo (pero como ahora suele estar oculto), mejor lo pones en una de las
clases que tienes en tu ensamblado.
Si lo usas desde C#, procura que esté fuera de cualquier definición de
espacios de nombres, y si lo usas desde Visual Basic, pues lo pones después de
todos los Imports que tengas en la clase.
Esta sería la forma de definirlo tanto en Visual Basic como en C#:
Imports System.Runtime.CompilerServices
<Assembly: InternalsVisibleTo("Nombre_del_ensamblado_amigo, PublicKey=la clave pública")>
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Nombre_del_ensamblado_amigo, PublicKey=la clave pública")]
En el nombre del ensamblado, debes poner el nombre del ensamblado desde el
que vas a usar las clases y miembros "internos" de este ensamblado. En la clave
pública debes poner la ristra de números de la clave pública del ensamblado con
el que quieres tener "amistad".
Los dos ensamblados deben estar firmados con nombre seguro. Y precisamente
esa clave pública es la clave pública con la que está firmado el ensamblado que
quieres "amigar".
Una vez que has hecho esa definición de el ensamblado que quieres que sea
"amigo", desde ese otro ensamblado podrás acceder a los miembros definidos con
Friend/internal.
Nota:
Puedes definir tantos ensamblados amigos como quieras, es decir, puedes usar
varios assembly: InternalsVisibleTo con los nombres y claves públicas que
quieras que puedan acceder a los miembros "internos" de tu ensamblado.
Pero recuerda que si usas Visual Basic 2005 solo puedes definirlos como amigos,
pero no usarlos.
Pero como te he comentado antes, si estás usando Visual Basic 2005, solo
puedes definir el ensamblado "amigable", pero no usarlo. Sin embargo con Visual
C# 2005 (o si lo prefieres con C# 2.0) si que puedes definir y usar ensamblados
amigos.
Para poder usar ensamblados amigos con Visual Basic, debes tener la versión
9.0 o sea, la que se incluye con Visual Studio Orcas., que algunos llaman Visual
Studio 2007, pero... no se yo si estará listo antes de que acabe el año...
Un ejemplo de todo lo aquí comentado
Para probar todo esto que te digo, te voy a explicar los pasos que debes
seguir.
Primero te explicaré cómo definir un ensamblado amigo desde Visual Basic
2005, el cual podrás usar desde C# 2005, ya que, como te he dicho antes, desde
Visual Basic 2005 solo podemos crear ensamblados amigos, pero no podemos
usarlos.
Después te voy a explicar cómo usar ese ensamblado desde Visual Basic 9.0
(para ello necesitarás Visual Studio Orcas).
Crear un ensamblado amigo con Visual Basic 2005
Abre el Visual Studio 2005 (no he probado con Visual Basic 2005 Express, y es
posible que también sea válido, pero no lo he probado), y crea un nuevo proyecto
de tipo Biblioteca de clases.
En el nombre le dices que se llame: InternalsVisibleTo01_vb.
En la clase por defecto que se crea, escribe todo este código (copia y pega):
' Prueba de InternalsVisibleTo (11/Abr/07)
Imports System.Runtime.CompilerServices
<Assembly: InternalsVisibleTo("InternalsVisibleTo02_cs, PublicKey=00240000048...")>
<Assembly: InternalsVisibleTo("InternalsVisibleTo03_cs, PublicKey=00240000048...")>
' Las clases, métodos o propiedades, etc. Friend (internal en C#) solo serán visibles
' para los ensamblados externos que se indiquen con InternalsVisibleTo.
Public Class Class1
Private m_Nombre As String
Friend Property Nombre() As String
Get
Return m_Nombre
End Get
Set(ByVal value As String)
m_Nombre = value
End Set
End Property
Public Function Saludo() As String
Return "Hola desde Class1.Saludo de Visual Basic"
End Function
Friend Function Saludo2() As String
Return "Hola desde Class1.Saludo2 de Visual Basic"
End Function
End Class
' Esta clase solo será visible si se usa InternalsVisibleTo
Friend Class Class2
Public Function Saludo() As String
Return "Hola desde Class2.Saludo de Visual Basic"
End Function
Friend Function Saludo2() As String
Return "Hola desde Class2.Saludo2 de Visual Basic"
End Function
End Class
Nota:
Fíjate que en PublicKey no he puesto la ristra completa de la clave pública, eso
lo tendrás que hacer tú, dependiendo de la clave usada para firmar esos
ensamblados.
Fíjate en el código anterior. En la clase Class1 he definido la propiedad
Nombre como Friend, lo mismo que el método Saludo2. Y la clase
Class2 está
definida como Friend, lo mismo que el método Saludo2 de esa clase.
Si no puedes acceder a los ensamblados amigos, esos "elementos" definidos
como Friend solo serán accesibles a otras clases que estén en ese mismo
proyecto. Y cuando digo proyecto, me refiero a proyecto, no a solución, ya que
una solución es un grupo de varios proyectos.
Firmar el ensamblado con nombre seguro (strong name)
Este ensamblado debe estar firmado con nombre seguro, por tanto, vamos a
dejar que sea el propio Visual Studio el que defina una clave para esa firma.
En las propiedades del proyecto, (haciendo doble clic en My Project),
selecciona la ficha Signing (no se como se llama en español, pero te puedes
hacer una idea con la figura 1).
Figura 1. Firmar el ensamblado con nombre seguro
Marca la casilla Sign the assembly (firmar el ensamblado), y de la lista
despegable, selecciona <New...> (nuevo), te mostrará otro cuadro de diálogo
(como el de la figura 2).
Figura 2. Crear una clave de nombre seguro
Escribe Prueba.snk y quita la marca de "Protect my key..." (o haz lo que
quieras, pero yo la he quitado).
Pulsa en OK y se creará el fichero con las claves a usar para firmar el
ensamblado con nombre seguro.
Nota:
Si ya tienes una clave creada, la puedes usar, y lo que tendrías que hacer es
usar <Browse...> en el paso de la figura 1, buscarías el fichero y se haría una
copia en tu proyecto.
Cuando compiles ese ensamblado, se firmará con el nombre seguro (strong name)
que has indicado y estará listo para ser usado.
Una vez que has seguido estos pasos, ya tienes un ensamblado que permite "la
amistad entre otros ensamblados", esa amistad la tendrá con los ensamblados que
hayas indicado en los atributos <Assembly: InternalsVisibleTo.
Ahora vamos a crear un proyecto en C# que use ese ensamblado amigo.
Crear un proyecto en C# para usar el ensamblado amigo
Nota:
Si tienes el Visual Studio 2005, puedes añadir un nuevo proyecto a la solución
actual.
Si tienes el Visual C# 2005 Express, debes crear un nuevo proyecto y seguir
estos mismos pasos, aunque en el caso de añadir una nueva referencia, debes
buscar el ensamblado que antes se ha generado.
Crea un nuevo proyecto de Visual C# 2005 que sea de tipo consola, y dale el
nombre InternalsVisibleTo02_cs.
En las referencias, (References) pulsa en Add Reference... (agregar
referencia).
Te mostrará un cuadro de diálogo con varias fichas, selecciona la ficha "Projects"
(proyectos), te mostrará los proyectos que tienes en la solución, por tanto,
selecciona el que hemos creado antes.
Este proyecto (ensamblado) debe estar firmado con nombre seguro, por tanto, o
bien usas un fichero de claves que ya tengas, o bien creas uno nuevo siguiendo
los pasos que te he indicado antes.
Para simplificar, crea un nuevo fichero de claves que se llame PruebaCS.snk
(ya sabes los pasos que debes dar).
Una cosa IMPORTANTE es que la clave pública de este
ensamblado debe ser la misma que hemos indicado en el proyecto anterior.
Ahora te explico cómo hacerlo.
Para probar las clases que hemos definido en el proyecto anterior, escribe el
siguiente código:
using System;
using System.Collections.Generic;
using System.Text;
using InternalsVisibleTo01_vb;
namespace InternalsVisibleTo02_cs
{
class Program
{
static void Main(string[] args)
{
Class1 c1 = new Class1();
c1.Nombre = "elGuille";
Console.WriteLine(c1.Nombre);
Console.WriteLine(c1.Saludo());
Console.WriteLine(c1.Saludo2());
Class2 c2 = new Class2();
Console.WriteLine(c2.Saludo());
Console.WriteLine(c2.Saludo2());
Console.ReadKey();
}
}
}
Si pruebas a compilar este proyecto (haz que sea el predeterminado),
seguramente te dará error diciéndote que Nombre es privado, que Class2 es
privada, etc.
Ese es el comportamiento "normal" para ensamblados que no son "amigos".
Para que este ensamblado se "confraterne" con el otro, (puedes
hacer que los dos se vayan de copas), (ya está el
otro Guille molestando...) debemos averiguar cual
es la clave pública con la que acabamos de firmar este proyecto y usar ese valor
en el proyecto anterior.
Si has seguido los pasos que te he recomendado, el proyecto de C# lo habrás
firmado con un fichero de claves llamado PruebaCS.snk.
Ahora vamos a averiguar la clave pública que tiene ese fichero para usarlo en
el proyecto de Visual Basic.
Abre el acceso directo a la línea de comandos de Visual Studio 2005, o la
ventana de comandos que te permita acceder al fichero sn.exe.
En mi instalación de Windows Vista con Visual Studio 2005 y el SDK de Windows
6.0 (el que sirve para usar el .NET Framework 3.0), lo tengo en: C:\Program
Files\Microsoft SDKs\Windows\v6.0\Bin, pero es posible que lo tengas en C:\Program
Files\Microsoft Visual Studio 8\SDK\v2.0\Bin.
Sea como sea, procura poder ejecutar sn y que no te de error.
En esa ventana de comandos, cambia a la unidad y directorio donde tengas el
proyecto de C# que acabas de crear.
En ese directorio estará el fichero PruebaCS.snk.
Escribe lo siguiente (acuérdate de pulsar la tecla INTRO
después de escribir eso):
sn -p PruebaCS.snk PruebaCS.publickey
Esto creará un fichero binario con la clave pública.
Ahora escribe lo siguiente:
sn -tp PruebaCS.publickey >PruebaCS.publickey.txt
Con esto lo que haces es exportar la clave pública a un fichero (si no usas
el >PruebaCS.publickey.txt, te lo mostrará en la misma ventana).
Abre ese fichero con el bloc de notas (u otro editor de textos), y fíjate que
el contenido será parecido al siguiente:
Microsoft (R) .NET Framework Strong Name Utility Version 2.0.50727.312
Copyright (c) Microsoft Corporation. All rights reserved.
Public key is
00240000048000009400000006020000002400005253413100040000010001001700669fa32c51
26d4e265b3983dcc0922ea414a0ef0e906356b48668e8f28694902943cd2a6fa35d673cfe0dcd5
6e8af08752dfee6e1b54f7afa666d26818e3f3291e9c8e392513581c7bedb7145b7c4152137602
f8d76de71ba802e7f72bacc6ba6bea471da2151bcac15907dac77292f1d9220d4f8bc489745366
abdca3c8
Public key token is 1766a08f664411c1
Lo que tienes que hacer es unir la ristra de números que hay bajo "Public key
is" y copiarla.
Esa ristra de números es la que tienes que poner después del signo igual
(donde están los tres puntos suspensivos) en:
<Assembly: InternalsVisibleTo("InternalsVisibleTo02_cs, PublicKey=...")>
Recuerda que ese atributo está en el proyecto InternalsVisibleTo01_vb.
Ahora compila todo el proyecto nuevamente y verás que puedes usar desde el
proyecto de C# las clases y métodos Friend del proyecto de Visual Basic.
Nota:
Si estás usando las versiones Express de Visual Basic 2005 y Visual C# 2005,
tendrás que compilar primero el proyecto de Visual Basic y asegurarte de que el
proyecto de C# tiene una referencia al ensamblado de Visual Basic. Después de
añadir (o actualizar) la referencia, puedes ejecutar el proyecto de C# y verás
que funciona.
Usar un ensamblado amigo desde Visual Basic 9.0 (Orcas)
Como te he comentado antes, en Visual Basic 2005 NO se pueden usar
ensamblados amigos, aunque sí crearlos.
Pero con Visual Basic 9.0 (el que se incluye en Visual Studio Orcas) si que
puede usarlos.
Si tienes el Visual Studio Orcas (lo puedes bajar e instalar), abre el
proyecto InternalsVisibleTo01_vb (te mostrará un aviso diciendo que lo tendrás que convertir,
así que... lo conviertes...).
Añade un nuevo proyecto de tipo consola y dale el nombre InternalsVisibleTo02_vb.
En ese proyecto, tendrás que agregar un fichero de nombre seguro, (sigue los
mismos pasos que te he explicado antes), además de averiguar la clave pública.
Para simplificar, puedes usar la misma clave que has creado en el proyecto de
C# y usar esos mismos valores... pero si quieres crear uno nuevo... pues... ya
sabes que tienes que seguir los pasos que te he indicado antes en
Averiguar la clave pública de un fichero de claves.
Ahora añade una referencia al proyecto anterior "InternalsVisibleTo01_vb" de Visual Basic.
Por último, pega este código en el fichero Module1 que tendrás en ese
proyecto de consola.
' En Visual Basic 2005 no se puede usar InternalsVisibleTo
' pero si en Visual Basic 9.0 (Visual Studio Orcas)
Imports InternalsVisibleTo01_vb
Module Module1
Sub Main()
Dim c1 As New Class1
c1.Nombre = "elGuille"
Console.WriteLine(c1.Nombre)
Console.WriteLine(c1.Saludo())
Console.WriteLine(c1.Saludo2())
Dim c2 As New Class2
Console.WriteLine(c2.Saludo())
Console.WriteLine(c2.Saludo2())
Console.ReadKey()
End Sub
End Module
Si ejecutas el proyecto verás que te dará error.
No es que esté mal, sino que en el proyecto de la librería de clases (InternalsVisibleTo01_vb)
debes decirle que ese ensamblado es amigo de este nuevo.
Por tanto, tendrás que añadir la siguiente línea al fichero del proyecto
anterior:
<Assembly: InternalsVisibleTo("InternalsVisibleTo02_vb, PublicKey=...")>
Y poner en los puntos suspensivos el número con la clave pública del fichero
de claves que hayas usado para firmar el proyecto InternalsVisibleTo02_vb.
Nota:
En el ZIP con el código de ejemplo para Visual Studio Orcas he usado el mismo
fichero de claves que el de C#.
Ahora vuelve a compilarlo todo (o simplemente pulsa F5) y verás que todo
funciona bien.
Y esto es todo... espero que haya quedado bien claro y que te sea de
utilidad.
Nos vemos.
Guillermo
Espacios de nombres usados en el código de este artículo:
System.Runtime.CompilerServices