Reflection e assembly

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, NothingNothing)

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, NothingNothing)

            
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 ObjectByVal spesa As DecimalByVal 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 TypeAs MethodInfo()
        
Dim flags As MethodFlags() = DirectCast([Enum].GetValues(GetType(MethodFlags)), MethodFlags())
        
Dim methods As MethodInfo() = New MethodInfo(flags.Length - 1) {}

        
For Each 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!"){}
    }
}

«August»
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678