Pagina 1 di 3 1 2 3 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 24
  1. #1

    [C#] Type dinamico per un foreach in Reflection.MethodInfo

    Continuano le mie avventure nel mondo dinamico del C#

    Dopo aver risolto il problema di tipo di dato dinamico me ne ritrovo un altro, il caricamento dinamico di una classe.

    In base ad una stringa contenente il nome di una classe vorrei caricare questa dinamicamente ed in base a questo nome vorrei generare un'istanza di tale classe o perlomeno sapere i metodi.

    Staticamente zero problemi, dinamicamente un disastro, ho provato i vari Assembly e mi son letto 10 pagine di triks and tips (più che altro trips ...) per fare quanto serve a me, solo che non c'ho capito quasi niente.

    Qualcuno sa darmi qualche dritta o spiegarmi quali classi o quali metodi devo studiarmi per fare quanto stò tentando di fare ?

    Riassunto:

    1 - caricare una classe C# in modo dinamico (precompilata ... o se possibile, anche non precompilata, un file .cs)

    2 - prendere il tipo di classe caricata , ovvero un typeof(ClasseCaricata) dove ClasseCaricata non può essere stringa ma il nome della classe ... e questa è quella che proprio non riesco a fare


    grazie
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  2. #2
    ho detto qualcosa di strano ? :master:
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  3. #3
    beh ... c'è svariata roba online anche se ho faticato un po a capire come dovevano essere caricate le assembly correttamente

    hai 2 modi per caricare in memoria degli assembly:
    1° - metodo abbastanza facile ma che ti da poca sicurezza e non ti permette di scaricare gli assembly caricati ... viene caricato tutto nel dominio corrente

    2° - metodo molto più complesso ma che ti permette non solo di avere un dominio di esecuzione separato quindi un'ambiene più stretto e controllato ma puoi anche scaricare in blocco questo dominio per ricaricarlo, nel caso ad es di gestione dei plugin o simili

    il 1° metodo te lo posto qua stesso, per il secondo vediamo quando ho + tempo ti spiego come fare, se ti interessa, ma è abbastanza complicato

    ad esempio il primo sistema lo uso nel mio software di backup per caricarmi i provider vari che mi gestiscono in blocco la copia dei file

    Ci sono 2 parti:
    - un'interfaccia, che devono implementare TUTTE le classi che vuoi utilizzare all'interno degli assembly
    - un gestore, che ti esegua il caricamento e ti gestica le operazioni comuni per semplificarti la vita

    Inoltre, dipende da come imposti il tutto, puoi anche avere una sola classe che ti interessa gestire esternamente e quindi semplicemente, come faccio in questi casi, il nome della classe è l'ultima parte nel nome dell'assembly

    Ad es
    xyz.BAS.BackupProviders.SimpleCopy

    la classe è SimpleCopy

    al gestore tu passi la stringa SimpleCopy e lui carica l'assembly xyz.bas.backupprovider.simplecopy e la classe (passandogli il fullname, quindi compreso il namespace) xyz.bas.backupprovider.simplecopy

    altrimenti hai 2 opzioni:
    - usi gli attributi per definire delle classi che sono visibili all'esterno, dove magari metti una descrizione ed un codice
    - usi la reflection per enumerare i metodi che estendono delle specifiche interfacce/classi

    ora ti posto il codice più semplice che c'è per farti un po capire

    codice:
    using System;
    using System.Reflection;
    using System.IO;
    
    namespace Computering.BAS.Helper
    {
    	/// <summary>
    	/// Descrizione di riepilogo per Interface.
    	/// </summary>
    	public class BackupProviderManager
    	{
    		public static string[] EnumerateProviders()
    		{
    			string[] fileNames = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "Computering.BAS.Helper.BackupProvider.*.dll");
    			for(int currentIndex = 0; currentIndex < fileNames.Length; currentIndex++)
    			{
    				fileNames[currentIndex] = Path.GetFileNameWithoutExtension(fileNames[currentIndex]);
    			}
    
    			return fileNames;
    		}
    
    		public static IBackupProvider LoadProvider(string providerName)
    		{
    			string baseDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    
    			if (File.Exists(baseDirectory + "\\" + providerName + ".dll") == false)
    			{
    				throw new FileNotFoundException("Impossibile caricare il provider " + baseDirectory + "\\" + providerName + ".dll", baseDirectory + "\\" + providerName + ".dll");
    			}
    			
    			IBackupProvider backupProviderInterface = (IBackupProvider)(Activator.CreateInstanceFrom(baseDirectory + "\\" + providerName + ".dll", providerName)).Unwrap();
    
    			return backupProviderInterface;
    		}
    	}
    }
    il codice sicuramente non è il massimo, anzi, però è abbastanza semplice da capire:
    - il primo mi elenca semplicemente i provider
    - il secondo mi carica il provider

    Tutto si può concentrare in una sola riga
    IBackupProvider backupProviderInterface = (IBackupProvider)(Activator.CreateInstanceFrom(bas eDirectory + "\\" + providerName + ".dll", providerName)).Unwrap();

    nel mio caso, ad esempio per simplecoy, providerName corrisponde a
    Computering.BAS.Helper.BackupProvider.SimpleCopy

    lo salvo per intero e lo uso per caricare il tutto

    ovviamente usando questo sistema potrei caricare un'assembly mio all'interno del tuo software e fare QUALSIASI tipo di danno e accedere a qualsiasi tipo di dato, ma non avendo dati di alcun genere all'interno del mio software non mi interessa più di tanto

    passiamo al caricamento tramite attributi e controllo estensione classe/interfaccia

    sono MOLTOOO simili, l'85% del codice è uguale e comunque se si usano gli attributi, in ogni caso, il secondo deve comunque essere controllato onde evitare rischi e problemi

    codice:
    Assembly loadedAssembly = Assembly.LoadFile(path);
    in questo modo carichi un'assembly e ti viene restituito l'oggetto. Se per qualche motivo potessi conservare solo il nome ti basta ciclare tutte le assembly caricate, tramite il metodo AppDomain.CurrentDomain.GetAssemblies, e confrontare i nomi o la location in base a quello che hai

    Acquisito l'oggetto assembly è tutto abbastanza facile ...
    codice:
    			foreach(Type foundedType in loadedAssembly.GetTypes())
    			{
    				if (foundedType.IsClass == true)
    				{
    					MessageBox.Show(foundedType.FullName + ":" + foundedType.IsSubclassOf(typeof(IBackupProvider)).ToString());
    				}
    			}
    con questo semplice codice ti cicli tutti i tipi contenuti nell'assembly e quelli che sono classi vengono stampati a video e li viene scritto il loro nome per intero e se sono sotto classi di IBackupProvider.
    IBackupProvider non è un'interfaccia ma una classe astratta, mi serviva che venisserò implementate delle funzionalità a priori. Comunque modificare il codice per verificare un'interfaccia è molto semplice ... non so se puoi lasciare questo identico codice cmq ti basta fare
    foundedType.GetInterface("nomeInterfaccia", true)

    e verificare se restituisce null
    (il secondo parametro verifica il casing del testo o meno)

    a questo codice, se vuoi verificare gli attributi, ti basta lavorare con
    foundedType.GetCustomAttributes(tipodacercare, false)

    il tipo lo recuperi facendo
    typeof(attributo)

    a quel punto, dopo che trovi le classi che ti interessano, puoi fare quello che ti serve ovvero instanziare le classi stesse usando il codice di sopra

    spero di averti chiarito qualche dubbio
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  4. #4
    Originariamente inviato da daniele_dll
    spero di averti chiarito qualche dubbio
    altro che ... ho fatto la parte che mi interessava, ma ora mi viene in mente un altro dubbio



    in pratica dopo di questo:
    Assembly loadedAssembly = Assembly.LoadFile("MiaClasse.dll");


    ho tante informazioni e credo di aver di fatto caricato l'oggetto ... ma devo per forza usare Activator o posso già teoricamente sfruttarlo ?

    MiaClasse pippo = new MiaClasse();

    posso farlo senza problemi ?
    (lo so, probabilmente è no e magari bastava testare ... è che non riesco a compilare stè dannate dll dalle classi )
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  5. #5
    Semplicemente chiama il compilatore da riga di comando dandogli tutti i parametri del caso. Tuttavia che funzione pratica può avere una cosa di questo tipo? Nessuna. Già la reflection io l'ho usata solo per caricare dinamicamente un provider per database piuttosto che un altro e relative chiamate a stored procedure o query (nel caso di MySql <=4).
    Ma ora sto anche pensando di abbandonarla per una gestione basata su xml.

  6. #6


    se usi la versione web developer non credo che tu possa compilare le librerie

    comunque no, non puoi farlo, devi usare o l'activator o qualche altra cosa

    ci sono svariati altri modi per instanziare le classi, credo sia possibile farlo direttamente dall'oggetto assembly

    xo è perfettamente uguale perché tanto se è già caricata l'assembly viene usata quella caricata
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  7. #7
    Originariamente inviato da markitos.net
    Semplicemente chiama il compilatore da riga di comando dandogli tutti i parametri del caso. Tuttavia che funzione pratica può avere una cosa di questo tipo? Nessuna. Già la reflection io l'ho usata solo per caricare dinamicamente un provider per database piuttosto che un altro e relative chiamate a stored procedure o query (nel caso di MySql <=4).
    Ma ora sto anche pensando di abbandonarla per una gestione basata su xml.
    ti assicuro che caricare dinamicamente gli assembly ed instanziare automaticamente delle interfacce specifiche è fondamentale per fornire flessibilità e dare la possibilità di implementare plugins

    ad esempio potresti sviluppare un'interfaccia standard per gestirti i vari provider e poi carichi l'assembly specifica che ti serve per gestire il database che si occupi di far tutto in modo che semplifichi il codice e hai maggiore flessibilità
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  8. #8
    E' esattamente ciò che ho fatto. Ma la soluzione mi sembra troppo arzigogolata. Solo che non ho basato lo sviluppo su interfacce ma su classi astratte (nelle interfacce devi implementare TUTTI i metodi, nelle abstract no e ti da una serie di vantaggi). Può essere gestita allo stesso modo attraverso una configurazione accurata. Certo, il codice va lavorato con cura, ma, nel caso, per esempio, di apllicazioni web, che richiedono (come mi è già capitato) transazioni su vari database e 2 phase commit caricare i provider con reflection ammazza il server già con solo qualche utente che effettuano le chiamate contemporaneamente.

    Non ho mai sviluppato plugin di sorta, quindi non so come funzioni la loro architettura. Può darsi che in questo caso la reflection sia senz'altro utile. Ma non certo la compilazione dinamica delle classi: ogni plugin deve avere una funzinalità prestabilita e per avere funzionalità dinamica ti puoi affidare agli script.

    Comunque è solo una mia personale opinione, sia chiaro

    Saluti

  9. #9
    Originariamente inviato da markitos.net
    E' esattamente ciò che ho fatto. Ma la soluzione mi sembra troppo arzigogolata. Solo che non ho basato lo sviluppo su interfacce ma su classi astratte (nelle interfacce devi implementare TUTTI i metodi, nelle abstract no e ti da una serie di vantaggi). Può essere gestita allo stesso modo attraverso una configurazione accurata. Certo, il codice va lavorato con cura, ma, nel caso, per esempio, di apllicazioni web, che richiedono (come mi è già capitato) transazioni su vari database e 2 phase commit caricare i provider con reflection ammazza il server già con solo qualche utente che effettuano le chiamate contemporaneamente.

    Non ho mai sviluppato plugin di sorta, quindi non so come funzioni la loro architettura. Può darsi che in questo caso la reflection sia senz'altro utile. Ma non certo la compilazione dinamica delle classi: ogni plugin deve avere una funzinalità prestabilita e per avere funzionalità dinamica ti puoi affidare agli script.

    Comunque è solo una mia personale opinione, sia chiaro

    Saluti
    su questo sono pienamente d'accordo, andare a fare il caricamento dinamico per i siti web è da suicidio ma sotto certi punti di vista è quasi l'unico sistema efficace per avere flessibilità per creare siti "modulari"

    comunque siccome non aveva tirato in ballo la questione web la cosa non l'ho scritta, so che sta usando il visual web developer express perché parlo spesso con lui ^^
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  10. #10
    Originariamente inviato da markitos.net
    Tuttavia che funzione pratica può avere una cosa di questo tipo?
    ma perchè se non sapete lo scopo date pareri ? :master:



    cmq sia non si tratta di compilare, se prendi l'assembly è già compilato, si tratta di caricare esternamente in modo dinamico ... scopo ultimo mio personale ?

    farmi le ossa con C# per ASP.NET (ci stò giocando, mi stò esercitando) e fare il porting di AJSHP per C#
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.