2012-12-14 16 views
5

Ich entwickle eine Desktop-Anwendung, die einem plugin-basierten System ähnlich ist. Ich habe ein Client-Modul, das eine DLL lädt, die ein "Machine" -Objekt enthält. Danach wird das Objekt 'Maschine' manipuliert und wie für gut definierte Schnittstellen verwendet.Übergabe von Daten zwischen Objekten in C#

Der schwierige Teil ist, dass die DLL, die das 'Maschine' Objekt enthält, im laufenden Betrieb erzeugt wird, indem ein anderes Programm verwendet wird. Im Kern akzeptiert die DLL-generierende Anwendung Benutzereingaben, generiert Klassen in C# -Codedateien (die Felder enthalten, die vom Benutzer angegeben wurden und von denen ich keine Vorkenntnisse habe) und kompiliert diese Klassen zu einer DLL (Maschine). DLL-Datei).

Das Client-Programm nimmt diese DLL auf, lädt sie dynamisch und arbeitet dann auf dieser Maschine.

Ich habe eine Menge Probleme bei der Modellierung einer Lösung, um das Problem der Übergabe von Daten zwischen dem Objekt Machine und dem Client-Programm zu lösen, im Wesentlichen, weil ich nicht weiß, welche Daten in dem Maschinenobjekt enthalten sind.

Das Client-Programm soll folgende Dinge tun.

- Laden Sie die DLL und instanziieren Sie das Objekt 'Maschine'. - Rufen Sie eine Reihe von Funktionen im Objekt 'Maschine' auf, die dem Client über eine Schnittstelle bekannt sind. - Extrahieren Sie verschiedene Variablen aus dem Objekt 'Maschine' und zeigen Sie sie dem Benutzer an.

Ich kann den letzten Schritt nicht ausführen.

Hinweis: Ich habe eine triviale Lösung programmiert, bei der die Metadaten zu den Feldern vom DLL-erzeugenden Programm generiert und in XML-Dateien gespeichert werden. Das Client-Programm verwendet diese XML-Dateien, um Informationen zu den im Maschinenobjekt gespeicherten Feldern abzurufen. Dann greift er auf das Maschinenobjekt zurück, um auf die Felder des Objekts zuzugreifen.

Ich fühle das ist umständlich und langsam. Gibt es irgendwelche Muster oder Methoden für diese Art von Sachen?

+0

Haben Sie sich das Managed Extensibility Framework (MEF) angesehen? http://mef.codeplex.com/ http://msdn.microsoft.com/en-us/library/dd460648.aspx – spender

+0

Ich habe davon gehört, und ich habe eine kurze Vorstellung davon ist die Verwendung. Die Sache ist, dass ich neu in der Programmierung bin und eine Lösung implementieren möchte, die leicht auf andere Sprachen und Systeme übertragbar ist. Außerdem möchte ich wirklich lernen, diese komplexen Systeme zu implementieren. –

+0

Durch die Implementierung in C# kann es auf andere Systeme portiert werden, da Mono vorhanden ist. Dies ist ein Port des .NET-Frameworks, das auf Linux und anderen Plattformen ausgeführt wird. Ich würde mich nicht unbedingt darum sorgen, es so generisch zu machen, dass es schnell in andere Sprachen portiert würde. Jede Sprache und Plattform hat ihre eigenen Idiome und Best Practices, und etwas, das in einem gut funktioniert, kann in einem anderen nicht gut funktionieren. –

Antwort

3

Eine Lösung, die in den Sinn kam, als ich gelesen Dies war, um die eingebaute Unterstützung für Attributes in C# zu verwenden. Ein Attribut ist eine Möglichkeit, eine Eigenschaft, ein Feld, eine Methode, eine Klasse usw. mit einigen zusätzlichen Metadaten zu versehen, die dann von einer anderen Klasse verwendet werden, zum Beispiel während Serialization. Du wirst es dort am häufigsten sehen.

Ich hatte eine Anwendung, die ich baute, die in der Lage sein musste, eine IEnumerable Sammlung von Objekten zu nehmen und einige Daten in eine Datei basierend auf benutzerdefinierten Auswahlmöglichkeiten auszugeben. Ich habe eine Attributklasse erstellt, die mir die Möglichkeit gab, die Auswahl durch Reflexion zu lesen und wie angewiesen zu handeln.Lassen Sie mich Ihnen ein Beispiel zeigen:

Zuerst wird die Attributklasse:

[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; 
    } 
} 

Mit dieser Klasse wie so definiert, konnte ich meine Datenklasse Eigenschaften wie diese dekorieren (tatsächlichen Eigenschaften verändert, um nicht auf verloren zu das Business-Jargon):

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; } 
} 

Also dann in meine Export Routine, statt Fest-Codierung der Eigenschaftsnamen, die variabel sind, oder eine komplexe Datenstruktur vorbei, um die sich die Informationen enthalten, auf die Felder ein- oder ausblenden und was das Ordnen war, ich habe einfach den folgenden Code unter Verwendung der Reflektion ausgeführt, um die Eigenschaften zu loopen und ihre Werte in diesem Fall in eine CSV-Datei auszugeben.

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"); 
} 

Der Code für die OrderedProperties struct hier:

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

Wie Sie die Logik sehen können, die Eigenschaftswerte zu extrahieren, völlig unwissend über die Struktur der Klasse ist. Es werden nur die Eigenschaften gesucht, die mit dem von mir erstellten Attribut versehen sind, und damit die Verarbeitung gesteuert.

Ich hoffe, das alles macht Sinn, und wenn Sie weitere Hilfe oder Klärung benötigen, zögern Sie nicht zu fragen.

+0

Sie generieren den Code, ohne zu wissen, was die Eigenschaften des Objekts sind, das an Sie gesendet wird. Um Ihre Lösung in meinem Programm verwenden zu können, muss ich mein codeerzeugendes Modul so ändern, dass diese Attribute in die CS-Dateien eingeschlossen werden, die ich gerade generiere. Ich werde das jetzt umsetzen. Vielen Dank. Aber kennen Sie andere Methoden, um das gleiche auf eine viel tiefere Art und Weise zu tun. Tut der Compiler nicht das, was ich tue, aber ein bisschen intrinsischer? Ich bezweifle, dass es auch Reflexion verwendet. Habe ich recht?? –

+1

Ja, das wäre richtig. Aber der Kompromiss ist eine viel einfachere Verarbeitung an Ihrem Ende. Stellen Sie sich Attribute als stapelbare Metadaten für Ihre Felder und Methoden vor.Solange Sie wissen, welche Attribute zu erwarten sind, können Sie Ihre Daten durchsuchen und anzeigen, während Sie sehr wenig über die tatsächlichen Objekte wissen, die an Sie zurückgegeben werden. [Die Werte der Attribute können auch zur Laufzeit festgelegt werden, wenn Sie benötigen.] (Http://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime) –

+0

Wissen Sie, wie Sie das Obige implementieren? Lösung in c/C++ ?? Oder vielleicht Dokumentation, die relevant ist für das, was Sie getan haben? Ich bestehe auf c/C++, weil das Codieren in diesen Sprachen es sehr einfach macht, die Funktionsweise der Lösung auf einer narrow-bones Ebene zu verstehen. –

2

Sie können auch ZeroMQ abholen, eine einfache MQ-Software, die die Kommunikation zwischen Anwendungen ermöglicht. ZeroMQ enthält nur 1 DLL, und Sie können in jede Ihrer Anwendungen eingebettet werden.

ZeroMQ hat alle Arten von Clients umfassen C, C++, .NET, Python, Java, Ruby und kann sowohl in Windows/Linux/OSX laufen ..

+0

Ist ZeroMQ nicht besser für Web-Apps geeignet? Meine Anwendung ist eine Desktop-Anwendung. –

+3

nein, es ist für die Anwendung geeignet, aber nicht für das Web, es ist eingebettet. –

+0

Ok. Es scheint, dass die Verwendung von Sockets genauso leistungsintensiv ist wie die Verwendung von Reflektion. –

Verwandte Themen