A volte potrebbe tornare utile utilizzare librerie .NET (assembly) sviluppate da terzi o da noi stessi con la versione precedente del Framework .NET oppure da differenti linguaggi tra C# & VB o viceversa. Il sostanza la Reflection rende portabile gli assembly in altra applicazione .NET senza bisogno di aggiungere la libreria tra i riferimenti nel progetto di Visual Studio, ma è sufficiente aggiungere fisicamente l'assembly nella directory bin dell'applicazione oppure indicare il path della directory.
Dim assemblyVer1x As [Assembly] = [Assembly].Load("AssemblyVer1x")
oppure
Dim assemblyVer1x As [Assembly] = [Assembly].LoadFrom("C:\Temp\AssemblyVer1x.dll")
Per accedere alla classe Assembly bisogna importare nella nostra classe il namespace:
Imports System.Reflection
In seguito si sceglie il tipo contenuto nell'assembly da cui successivamente ottenerne l'istanza ed invocare metodi o interagire con proprietà.
Dim tp As Type = assemblyVer1x.GetType("AssemblyVer1x.Persona", True)
E possibile passare un array (argsCostructor) di argomenti che contengono parametri del costruttore come nel nostro caso della classe AssemblyVers1x.Persona
Dim istance As Object = assemblyVer1x.CreateInstance(tp.FullName, True, _ BindingFlags.CreateInstance, Nothing, argsCostructor, Nothing, Nothing)
Va preso in considerazione che prima bisogna ottenere tutte le informazioni dei nomi dei tipi e membri della classe AssemblyVers1x.Persona
Dall' oggetto Type è possibile recuperare le istanze PropertyInfo o MethodInfo in modo da interagire con proprietà e metodi della classe AssemblyVers1x.Persona
Dim properties As PropertyInfo() = New PropertyInfo(1) {}
properties(0) = tp.GetProperty("Nome")
properties(1) = tp.GetProperty("Cognome")
Dim nome As String = CType(properties(0).GetValue(istance, Nothing), String)
Dim cognome As String = CType(properties(1).GetValue(istance, Nothing), String)
A questo punto si può continuare ad esplorare e testare la libreria in modo da verificarne l'affidabilità.
Qui sotto riporto un esempio completo di una classe in VB8 che fa uso di una libreria scritta in C# 1.0
Option Explicit On
Option Strict On
Imports System.Reflection
Class TestReflection
Private Enum MethodFlags
IncassaStipendio
ControllaCassa
GetPortafoglio
FaiLaSpesa
VersaMutuoOAffitto
VersaTassa
End Enum
Shared Sub Main(ByVal args As String())
Try
Dim argsCostructor As Object() = New Object(1) {}
Console.Write("Inserisci il tuo nome: ")
argsCostructor(0) = Console.ReadLine()
Console.WriteLine()
Console.Write("Inserisci il tuo cognome: ")
argsCostructor(1) = Console.ReadLine()
Dim assemblyVer1x As [Assembly] = [Assembly].LoadFrom("C:\Temp\AssemblyVer1x.dll")
Dim tp As Type = assemblyVer1x.GetType("AssemblyVer1x.Persona", True)
Dim istance As Object = assemblyVer1x.CreateInstance(tp.FullName, True, _
BindingFlags.CreateInstance, Nothing, argsCostructor, Nothing, Nothing)
Dim properties As PropertyInfo() = New PropertyInfo(1) {}
properties(0) = tp.GetProperty("Nome")
properties(1) = tp.GetProperty("Cognome")
Dim nome As String = CType(properties(0).GetValue(istance, Nothing), String)
Dim cognome As String = CType(properties(1).GetValue(istance, Nothing), String)
Console.WriteLine()
Console.WriteLine("Benvenuto {0} {1}", nome, cognome)
Console.WriteLine()
Console.Write("Quanti euri hai percepito di stipendio in questo mese?: ")
Dim stipendio As Decimal = Convert.ToDecimal(Console.ReadLine())
Dim methods As MethodInfo() = TestReflection.LoadMethods(tp)
Dim status As Object() = New Object(0) {}
methods(MethodFlags.IncassaStipendio).Invoke(istance, New Object(0) {stipendio})
Dim tesoretto As Decimal = Convert.ToDecimal(methods(MethodFlags.GetPortafoglio).Invoke(istance, status))
Console.WriteLine()
Console.WriteLine("Complimenti, {0} euro {1}, visto i prezzi e tasse aumentano sempre si potrebbe cercare un aumentino di stipendio.", tesoretto, status(0))
Console.WriteLine()
Console.Write("Quanti euri intendi spendere di stipendio in questo mese?: ")
Dim spesa As Decimal = Convert.ToDecimal(Console.ReadLine())
TestReflection.Paga(methods, istance, spesa, MethodFlags.FaiLaSpesa)
Console.WriteLine()
Console.Write("Quanti euri devi pagare di affitto o mutuo in questo mese?: ")
spesa = Convert.ToDecimal(Console.ReadLine())
TestReflection.Paga(methods, istance, spesa, MethodFlags.VersaMutuoOAffitto)
Console.WriteLine()
Console.Write("Quanti euri devi pagare di tasse in questo mese?: ")
spesa = Convert.ToDecimal(Console.ReadLine())
TestReflection.Paga(methods, istance, spesa, MethodFlags.VersaTassa)
tesoretto = Convert.ToDecimal(methods(MethodFlags.GetPortafoglio).Invoke(istance, status))
Console.WriteLine()
Console.WriteLine("E gia {0} {1}! Con i rimanenti {2} euri al mese immagino " & _
"che il tuo stato d'animo diventi così {3}", nome, cognome, tesoretto, status(0))
Catch ex As FormatException
Console.WriteLine()
Console.WriteLine("Input non corretto. Riprova da capo.")
Catch ex As Exception
Console.WriteLine()
Console.WriteLine(ex.Message)
Finally
Console.WriteLine()
Console.Write("Premi un tasto per terminare")
Console.Read()
End Try
End Sub
Shared Sub Paga(ByVal methods As MethodInfo(), ByVal istance As Object, ByVal spesa As Decimal, ByVal methodIndex As Integer)
Try
methods(MethodFlags.ControllaCassa).Invoke(istance, New Object(0) {spesa})
methods(methodIndex).Invoke(istance, New Object(0) {spesa})
Catch ex As TargetInvocationException
Console.WriteLine(ex.InnerException.Message)
Console.WriteLine()
Console.Write("Sicuro di continuare? S/N: ")
Dim risposta As Char = Convert.ToChar(Console.ReadLine())
If Char.ToUpper(risposta) = "S"c Then methods(methodIndex).Invoke(istance, New Object(0) {spesa})
End Try
End Sub
Shared Function LoadMethods(ByVal tp As Type) As MethodInfo()
Dim flags As MethodFlags() = DirectCast([Enum].GetValues(GetType(MethodFlags)), MethodFlags())
Dim methods As MethodInfo() = New MethodInfo(flags.Length - 1) {}
For Each m As MethodFlags In flags
methods(m) = tp.GetMethod(String.Format("{0:G}", m))
Next
Return methods
End Function
End Class
using System;
namespace AssemblyVer1x
{
public class Persona
{
string nome, cognome;
Decimal stipendio = 0;
string[] faccine = {":-)",":-/"};
private enum Faccia{Allegra = 0,Triste = 1}
public Persona(string nome, string cognome)
{
this.nome = nome;
this.cognome = cognome;
}
public string Nome
{
get { return this.nome; }
set { this.nome = value;}
}
public string Cognome
{
get { return this.cognome; }
set { this.cognome = value;}
}
public void VersaTassa(decimal tassa)
{
this.stipendio -= tassa;
}
public void VersaMutuoOAffitto(decimal rata)
{
this.stipendio -= rata;
}
public void FaiLaSpesa(decimal spesa)
{
this.stipendio -= spesa;
}
public void IncassaStipendio(decimal stipendio)
{
this.stipendio += stipendio;
}
public Decimal GetPortafoglio(out string stato)
{
if (stipendio <=0)
stato = faccine[(int)Faccia.Triste];
else
stato = faccine[(int)Faccia.Allegra];
return stipendio;
}
public void ControllaCassa(Decimal importo)
{
Decimal differenza = this.stipendio - importo;
if (differenza<=0)
throw new SenzaUnCentesimoException();
}
}
public class SenzaUnCentesimoException : ApplicationException
{
public SenzaUnCentesimoException():base("Attenzione!" +
"Rischi davvero di non arrivare a fine mese!"){}
}
}