2012-12-14 7 views
5

Sto sviluppando un'applicazione per desktop simile a un sistema basato su plugin. Ho un modulo client, che caricherà una DLL contenente un oggetto 'Macchina'. Successivamente l'oggetto 'Macchina' viene manipolato e utilizzato come da interfacce ben definite.Passaggio di dati tra oggetti in C#

La parte difficile è che la DLL che contiene l'oggetto 'Machine' viene generato al volo utilizzando un altro programma. Al suo nucleo, l'applicazione di generazione DLL accetta input dell'utente, genera classi, in file di codice C# (che contengono campi specificati dall'utente, di cui non ho alcuna conoscenza precedente) e li compila in una DLL (macchina. file dll).

Il programma client raccoglie questa DLL, in modo dinamico lo carica e quindi opera su questo bject macchina.

Sto affrontando un sacco di problemi nella modellazione di una soluzione per risolvere il problema del passaggio di dati tra l'oggetto Machine e il programma Client, essenzialmente perché non so quali dati sono contenuti nell'oggetto macchina.

Il programma client è quello di fare le seguenti cose.

- caricare la DLL e istanziare l'oggetto 'macchina'. - Chiama una serie di funzioni nell'oggetto 'macchina', che sono note al client tramite un'interfaccia. - Estrai varie variabili dall'oggetto 'macchina' e mostrale all'utente.

Non riesco a eseguire l'ultimo passaggio.

Nota: Ho programmato una soluzione banale in cui la meta-dati sui campi è generata dal programma di generazione dll e memorizzati in file XML. Il programma client utilizza questi file xml per ottenere informazioni sui campi memorizzati nell'oggetto macchina. Quindi utilizza la riflessione sull'oggetto macchina per accedere ai campi dell'oggetto.

Sento che questo è ingombrante e lento. Ci sono schemi o metodi per questo genere di cose ??

+0

Hai visto il Managed Extensibility Framework (MEF)? http://mef.codeplex.com/ http://msdn.microsoft.com/en-us/library/dd460648.aspx – spender

+0

Ne ho sentito parlare e ho una breve idea del suo utilizzo. Il fatto è che sono nuovo alla programmazione e voglio implementare una soluzione che sia facilmente trasferibile ad altri linguaggi e sistemi. Inoltre, voglio davvero imparare a implementare questi sistemi complessi. –

+0

L'implementazione in C# la rende portabile ad altri sistemi in quanto vi è Mono, che è una porta del framework .Net che gira su Linux e altre piattaforme. Non mi preoccuperei necessariamente di renderlo così generico anche se portasse rapidamente in altre lingue. Ogni lingua e piattaforma ha il proprio set di idiomi e best practice e qualcosa che funziona bene in uno potrebbe non funzionare bene in un altro. –

risposta

3

Una soluzione che è venuto in mente quando ho letto questo è stato quello di utilizzare il supporto integrato per Attributes in C#. Un attributo è un modo di codificare una proprietà, un campo, un metodo, una classe, ecc. Con alcuni metadati aggiuntivi che vengono poi utilizzati da un'altra classe, ad esempio durante Serialization. Lo vedrai più spesso.

Avevo un'applicazione che stavo costruendo che doveva essere in grado di prendere una collezione di oggetti IEnumerable e produrre alcuni dati in un file in base alle scelte selezionate dall'utente. Ho creato una classe di attributi che mi ha dato la possibilità di leggere le scelte tramite la riflessione e agire come indicato.Lasciate che vi mostri l'esempio:

prima classe di attributo:

[System.AttributeUsage(AttributeTargets.Property)] 
class ExportOptionsAttribute : System.Attribute 
{ 
    public string Header { get; set; } 
    public string FormatString { get; set; } 
    public bool Export { get; set; } 
    public int Order { get; set; } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="header"></param> 
    public ExportOptionsAttribute(string header) : this (header, null, true) 
    { 

    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="header"></param> 
    /// <param name="formatString"></param> 
    /// <param name="export"></param> 
    public ExportOptionsAttribute(string header, string formatString, bool export) 
    { 
     this.Header = header; 
     this.FormatString = formatString; 
     this.Export = export; 
     this.Order = 0; 
    } 
} 

Con questa classe definita in questo modo, ho potuto decorare la mia proprietà di classe di dati come questo (reali proprietà modificate in modo da non perdersi su il business gergo):

public sealed class PartsOrder 
{ 
    /// <summary> 
    /// 
    /// </summary> 
    [ExportOptions("Customer Name", Order=0)] 
    public string CustomerName { get; set; } 

    /// <summary> 
    /// 
    /// </summary> 
    [ExportOptions("Catalog Name", Order = 1)] 
    public string Catalog Name { get; set; } 

    /// <summary> 
    /// 
    /// </summary> 
    [ExportOptions("Unit", Order = 2)] 
    public string Unit { get; set; } 

    /// <summary> 
    /// 
    /// </summary> 
    [ExportOptions("Component", Order = 3)] 
    public string Component { get; set; } 

    /// <summary> 
    /// 
    /// </summary> 
    [ExportOptions("Delivery Point", Order = 4)] 
    public string DeliveryPoint { get; set; } 

    /// <summary> 
    /// 
    /// </summary> 
    [ExportOptions("Order Date", Order = 5)] 
    public string OrderDate { get; set; } 
} 

allora nella mia routine di esportazione, invece di codificare i nomi delle proprietà, che sono variabili, o passando una struttura dati complessa attorno alla quale contiene le informazioni su quali campi per mostrare o nascondere e che ordine era, io è sufficiente eseguire il codice seguente, utilizzando reflection, per eseguire il loop delle proprietà e generare i relativi valori, in questo caso in un file CSV.

StringBuilder outputDoc = new StringBuilder(); 

// loop through the headers in the attributes 
// a struct which decomposes the information gleaned from the attributes 
List<OrderedProperties> orderedProperties = new List<OrderedProperties>(); 

// get the properties for my object 
PropertyInfo[] props = 
    (typeof(PartsOrder)).GetProperties(); 

// loop the properties 
foreach (PropertyInfo prop in props) 
{ 
    // check for a custom attribute 
    if (prop.GetCustomAttributesData().Count() > 0) 
    { 
     foreach (object o in prop.GetCustomAttributes(false)) 
     { 
      ExportOptionsAttribute exoa = o as ExportOptionsAttribute; 

      if (exoa != null) 
      { 
       orderedProperties.Add(new OrderedProperties() { OrderByValue = exoa.Order, PropertyName = prop.Name, Header = exoa.Header, Export = exoa.Export }); 
      } 
     } 
    } 
} 

orderedProperties = orderedProperties.Where(op => op.Export == true).OrderBy(op => op.OrderByValue).ThenBy(op => op.PropertyName).ToList(); 

foreach (var a in orderedProperties) 
{ 
    outputDoc.AppendFormat("{0},", a.Header); 
} 

// remove the trailing commma and append a new line 
outputDoc.Remove(outputDoc.Length - 1, 1); 
outputDoc.AppendFormat("\n"); 


var PartsOrderType = typeof(PartsOrder); 

//TODO: loop rows 
foreach (PartsOrder price in this.Orders) 
{ 
    foreach (OrderedProperties op in orderedProperties) 
    { 
     // invokes the property on the object without knowing the name of the property 
     outputDoc.AppendFormat("{0},", PartsOrderType.InvokeMember(op.PropertyName, BindingFlags.GetProperty, null, price, null)); 
    } 

    // remove the trailing comma and append a new line 
    outputDoc.Remove(outputDoc.Length - 1, 1); 
    outputDoc.AppendFormat("\n"); 
} 

Il codice per l'OrderedProperties struct è qui:

struct OrderedProperties 
{ 
    /// <summary> 
    /// 
    /// </summary> 
    public int OrderByValue; 
    /// <summary> 
    /// 
    /// </summary> 
    public string PropertyName; 
    /// <summary> 
    /// 
    /// </summary> 
    public string Header; 
    /// <summary> 
    /// 
    /// </summary> 
    public bool Export; 
} 

Come si può vedere, la logica per estrarre i valori delle proprietà è completamente ignaro della struttura della classe. Tutto ciò che fa è trovare le proprietà che sono decorate con l'attributo che ho creato e usarlo per guidare l'elaborazione.

Spero che tutto abbia un senso, e se hai bisogno di più aiuto o chiarimenti, non esitare a chiedere.

+0

Si sta generando il codice senza sapere quali sono le proprietà nell'oggetto che viene inviato all'utente. Quindi per usare la tua soluzione nel mio programma, devo cambiare il mio modulo di generazione del codice per includere questi attributi nei file .cs che sto generando al volo. Lo implementerò per ora. Grazie. Tuttavia, conosci altri metodi per fare la stessa cosa in un modo molto più di basso livello. Il compilatore non sta facendo ciò che sto facendo, ma un po 'più intrinsecamente? Dubito che stia usando anche la riflessione. Ho ragione?? –

+1

Sì, sarebbe corretto. Ma il compromesso è un insieme molto più semplice di elaborazione da parte tua. Pensa agli attributi come metadati impilabili per i tuoi campi e metodi.Finché sai quali attributi aspettarti, puoi fare il tuo munging di dati e visualizzarli pur sapendo molto poco degli oggetti reali restituiti. [Inoltre, i valori degli attributi possono essere impostati in fase di esecuzione se necessario.] (Http://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime) –

+0

Sai come implementare il suddetto soluzione in c/C++ ?? O forse la documentazione che è rilevante per ciò che hai fatto? Sto così insistendo su c/C++ perché la codifica in quei linguaggi rende davvero facile capire il funzionamento della soluzione a un livello più ridotto. –

2

È anche possibile raccogliere ZeroMQ, che è un software leggero MQ, ha permesso la comunicazione tra le applicazioni. ZeroMQ include solo 1 dll e puoi essere incorporato in una qualsiasi delle tue applicazioni.

ZeroMQ ha tutti i tipi di clientela, includono C, C++, .NET, Python, Java, Ruby, e può funzionare sia in Windows/Linux/OSX ..

+0

Non è ZeroMQ più adatto per le app Web? La mia applicazione è un'applicazione desktop. –

+3

no, è adatto per l'applicazione ma non per il web, è incorporato. –

+0

Ok. Sembra che l'uso di socket sia tanto intensivo quanto l'utilizzo del reflection. –