2012-12-14 77 views
5

我正在開發一個類似於基於插件的系統的桌面應用程序。我有一個客戶端模塊,它會加載一個包含'Machine'對象的DLL。此後,按照定義良好的界面操作和使用'機器'對象。在c中的對象之間傳遞數據#

棘手的部分是,包含'機器'對象的DLL是通過使用其他程序即時生成的。在它的核心,DLL生成應用程序接受用戶輸入,在c#代碼文件(包含用戶指定的字段,我沒有任何先前的知識)中生成類,並將這些類編譯到DLL(機器)。 dll文件)。

客戶端程序拿起這個DLL,動態加載它,然後在這臺機器上運行。

我正面臨着很多困難,建模解決方案來解決Machine對象和客戶端程序之間傳遞數據的問題,實質上是因爲我不知道機器對象中包含的數據。

客戶端程序將執行以下操作。

- 加載dll並實例化'machine'對象。 - 通過接口調用客戶端已知的「機器」對象中的一系列函數。 - 從「機器」對象中提取各種變量並將其顯示給用戶。

我無法執行最後一步。

注意:我已經編寫了一個簡單的解決方案,其中有關字段的元數據由dll生成程序生成並存儲在xml文件中。客戶端程序使用這些xml文件獲取有關存儲在機器對象中的字段的信息。然後它使用機器對象上的反射來訪問對象的字段。

我覺得這很麻煩而且很慢。這種東西有任何模式或方法?

+0

你看過託管擴展性框架(MEF)嗎? http://mef.codeplex.com/ http://msdn.microsoft.com/en-us/library/dd460648.aspx – spender

+0

我聽說過它,我對它的用法有個簡單的概念。問題是,我對編程不熟悉,我想實現一個易於移植到其他語言和系統的解決方案。另外,我想真正學會實施這些複雜的系統。 –

+0

在C#中實現它使得它可以移植到其他系統,因爲有Mono,它是在Linux和其他平臺上運行的.Net框架的一個端口。我並不一定擔心它會變得如此通用,儘管它可以快速轉換到其他語言。每種語言和平臺都有自己的一套成語和最佳實踐,而在一種語言和平臺中運行良好的東西在另一種語言和平臺中可能效果不佳。 –

回答

3

說來,當我讀心目中的解決方案這是爲了利用C#中的Attributes的內置支持。屬性是一種標記屬性,字段,方法,類等的方法,其中包含一些其他元數據,然後由其他類使用,例如在Serialization期間。你會經常在那裏看到它。

我有一個應用程序,我正在建設,需要能夠採取IEnumerable對象集合,並輸出一些數據到文件基於用戶選擇的選擇。我創建了一個屬性類,使我能夠通過反射來閱讀選擇,並按照指示行事。讓我告訴你的例子:

首先是屬性類:

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

,象這樣定義這個類,我可以裝飾我這樣的數據類屬性(實際性改變,以便不會迷路上商業行話):

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

所以後來在我出口常規,而不是硬編碼的屬性名稱,它是可變的,或經過一個複雜的數據結構,在其周圍包含了哪些字段,以顯示或隱藏信息以及排序是什麼,我在這種情況下,只需運行以下代碼(使用反射)將屬性循環並將其值輸出到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"); 
} 

爲OrderedProperties結構的代碼是在這裏:

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

正如你可以看到,提取屬性值的邏輯是完全不知道的類的結構。它所做的就是查找用我創建的屬性裝飾的屬性,並使用它來驅動處理。

我希望這一切都有道理,如果您需要更多幫助或澄清,請隨時詢問。

+0

您正在生成代碼而不知道發送給您的對象中的屬性是什麼。所以要在我的程序中使用您的解決方案,我必須更改我的代碼生成模塊,以將這些屬性包含在我即時生成的.cs文件中。我現在將執行此操作。謝謝。但是,你是否知道其他方法以更低級別的方式做同樣的事情?編譯器不是在做我正在做的事情,而是更具內在性?我懷疑它是否也在使用反射。我對嗎?? –

+1

是的,那是對的。但是,權衡是一個更簡單的處理集。將屬性視爲字段和方法的可堆棧元數據。只要你知道什麼樣的屬性值得期待,你就可以完成數據的傳遞,並且在知道返回給你的實際對象的時候顯示很少的數據。 [另外,如果需要,可以在運行時設置屬性的值。](http://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime) –

+0

你知道如何實現上述解決方案在C/C++?或者也許是與你所做的相關的文檔?我堅持使用c/C++,因爲使用這些語言進行編碼使得在更簡單的層面上理解解決方案的工作變得非常容易。 –

2

您還可以選擇ZeroMQ,這是一款輕量級MQ軟件,支持應用程序之間的通信。 ZeroMQ只包含1個DLL,你可以嵌入你的任何應用程序中。

ZeroMQ擁有所有類型的客戶端,包括C,C++,.NET,Python和Java的,紅寶石,並且可以在這兩個Windows/Linux的/ OSX運行..

+0

是不是ZeroMQ更適合網絡應用?我的應用程序是桌面應用程序。 –

+3

不,它適用於應用程序,但不適用於Web,它是嵌入式的。 –

+0

好的。似乎使用套接字將與使用反射一樣表現密集。 –