C # che collega dinamicamente diverse librerie e / o classi esterne

2

tl; dr

È possibile includere una libreria esterna (e creare istanze di oggetti rappresentati all'interno di quella libreria) in base ad alcune condizioni? Questo deve essere fatto in fase di compilazione, quindi build separati?

Informazioni di base

Avviso: muro di testo.

Se ho del codice che richiede un collegamento a una classe esterna:

using myExternalLibrary;
namespace myNamespace
{
  public class Engine
  {
     public Engine()
     {
       // external class is contained
       // within myExternalLibrary
       public externalClass instanceOfExternalClass
              = new externalClass();
     }
  }
}

// external class
namespace myExternalLibrary
{
  public class externalClass
  {
     public externalClass()
     {
       // constructor logic
     }
  }
}

Fornendo riferimenti a myExternalLibrary nel progetto che contiene myClass e fornendo un'istruzione using in un luogo pertinente, posso creare un'istanza di externalClass come e quando ne ho bisogno all'interno di myClass. Questo sto bene con. Se ho un codice molto comune che richiede diverse librerie esterne, posso fare la stessa cosa, ma con ciascuna delle librerie esterne richieste (cioè aggiungere un riferimento e un'istruzione using per ognuna delle librerie esterne).

Tuttavia, a causa della progettazione del software su cui sto lavorando, mi viene richiesto di utilizzare una libreria esterna solo quando sono soddisfatte determinate condizioni. Devo anche non includere riferimenti a quelle librerie esterne se non sono richieste.

Dettaglio classe

Non posso entrare nello specifico del design della classe, ma questo è fondamentalmente ciò che ho: ho una classe (questa è la classe Engine) che è necessaria per fungere da ponte tra la GUI e alcuni componenti hardware. La classe Engine richiede librerie esterne per consentirgli di comunicare con l'hardware esterno.

Ho due librerie esterne per due diversi tipi di hardware:

  • InternallyDevelopedHardwareControlLibrary (la nostra libreria hardware sviluppata internamente per il controllo dell'hardware sviluppato internamente)
  • LicensedHardwareControlLibrary (una libreria che abbiamo ottenuto in licenza per il controllo di alcuni componenti hardware acquistati in).

Per impostazione predefinita, il motore comunica tramite InternallyDevelopedHardwareControlLibrary al nostro hardware sviluppato internamente. Tuttavia, Engine deve anche essere in grado di comunicare tramite LicensedHardwareControlLibrary all'hardware con licenza, se (e solo se) l'utente finale ha concesso in licenza il nostro software per funzionare insieme all'hardware sviluppato esternamente.

LicensedHardwareControlLibrary sarà concesso in licenza all'utente finale con il nostro software ad alcuni dei nostri utenti finali. In questo caso, è necessario che LicensedHardwareControlLibrary sia spedito con il nostro software. Tuttavia, se l'utente finale non dispone della licenza per utilizzare LicensedHardwareControlLibrary, non è consentito spedire tale libreria con software esterno.

Poiché il motore sta sostituendo la comunicazione con l'hardware esterno tramite InternallyDevelopedHardwareControlLibrary, per impostazione predefinita richiede un riferimento. Tuttavia, se un utente è autorizzato ad utilizzare LicensedHardwareControlLibrary, ho bisogno di aggiungere un riferimento a questo, ma solo se l'utente è autorizzato ad usare quella libreria.

Domanda

Dato che il motore deve essere generico, devo trovare un modo per includere condizionatamente questa seconda libreria.

Il mio pensiero iniziale era di spostare tutti gli elementi di Engine in una classe astratta e di avere due motori separati (uno per ciascuna delle librerie) che estendono la classe Engine astratta. Qualcosa come:

public class Engine
{
  // all common code for each Engine
  // type in here
}

public class StandardEngine : Engine
{
  // the engine that will utilise
  // InternallyDevelopedHardwareControlLibrary
}

public class LicensedEngine : Engine
{
  // the engine that will utilise
  // LicensedHardwareControlLibrary
}

Il codice StandardEngine utilizzerà un'istanza degli oggetti rappresentati in InternallyDevelopedHardwareControlLibrary e LicensedEngine utilizzerà un'istanza degli oggetti rappresentati in LicensedHardwareControlLibrary.

O più semplicemente: ciascuna delle versioni meno astratte di Engine richiede di operare su una rappresentazione di un oggetto contenuto in InternallyDevelopedHardwareControlLibrary (StandardEngine) o LicensedHardwareControlLibrary (LicensedEngine).

La build standard conterrà solo la classe StandardEngine, tuttavia per alcuni utenti sarà necessario eseguire una build separata che contenga anche la classe LicensedEngine.

Tuttavia, ritengo che ciò non sia ottimale perché LicensedEngine dovrà essere esterno al progetto / libreria principale perché non può essere spedito nella nostra build standard. Quali sono i modi in cui posso ottenere questo?

    
posta Jamie Taylor 07.01.2014 - 13:05
fonte

1 risposta

2

Prendi prima una decisione importante: compila tempo o tempo di esecuzione?

Se si desidera utilizzare i riferimenti all'assembly, sono solo in fase di compilazione. Quindi è possibile utilizzare le direttive #if nel codice e utilizzare i trucchi MSBuild (modificare il file csproj all'esterno di Visual Studio) per disporre in modo condizionale del riferimento dell'assembly. MSBuild è uno strumento molto potente e, se stai attento, non farà troppo casino con Visual Studio. Oppure puoi semplicemente avere più file csproj, che vivono nella stessa directory, usando (quasi) gli stessi file sorgenti e diversi riferimenti. Tutto questo accade in fase di compilazione.

Un approccio completamente diverso sta facendo il caricamento di riferimento durante il runtime, ecco perché hanno inventato la riflessione. Sei fortunato se il riferimento esterno implementa un'interfaccia comune perché una volta ottenuto il tipo con il riflesso, puoi lanciarlo sulla tua interfaccia e usarlo normalmente. Altrimenti, sei bloccato con Invoke() -ing MethodInfo -s. Oppure, se i tuoi requisiti lo consentono, puoi creare un assembly di livello adattatore molto piccolo tra la libreria esterna e la tua come terzo assemblaggio. Se hai bisogno di utilizzare la libreria esterna, carichi dinamicamente l'assembly adapter, lo lanci su un'interfaccia e usi la libreria esterna attraverso quel layer, senza Invoke() ovunque.

    
risposta data 07.01.2014 - 13:11
fonte

Leggi altre domande sui tag