2012-12-14 22 views
5

Zajmuję się aplikacją pulpitu, która jest podobna do systemu opartego na wtyczkach. Mam moduł klienta, który załaduje bibliotekę DLL zawierającą obiekt "Machine". Następnie obiekt "Maszyna" jest manipulowany i używany zgodnie z dobrze zdefiniowanymi interfejsami.Przekazywanie danych między obiektami w C#

Trudnym elementem jest to, że biblioteka DLL zawierająca obiekt "Maszyna" jest generowana w locie przy użyciu innego programu. W jego rdzeniu, aplikacja generująca DLL akceptuje dane wejściowe użytkownika, generuje klasy, w plikach kodu C# (które zawierają pola określone przez użytkownika, z których nie posiadam żadnej wcześniejszej wiedzy) i kompiluje te klasy do biblioteki DLL (maszyna. plik dll).

Program kliencki pobiera tę bibliotekę dll, dynamicznie ładuje ją, a następnie uruchamia się na tym bipie.

Mam do czynienia z wieloma problemami podczas modelowania rozwiązania, które rozwiązuje problem przekazywania danych między obiektem maszyny a programem klienta, głównie dlatego, że nie wiem, jakie dane znajdują się w obiekcie maszyny.

Program kliencki wykonuje następujące czynności.

- Załaduj bibliotekę dll i stwórz obiekt "maszyny". - Wywołanie serii funkcji w obiekcie "maszyna", które są znane klientowi za pośrednictwem interfejsu. - Wyodrębnij różne zmienne z obiektu "maszyna" i wyświetl je użytkownikowi.

Nie jestem w stanie wykonać ostatniego kroku.

Uwaga: Zaprogramowałem trywialne rozwiązanie, w którym meta-dane o polach są generowane przez program generujący dll i przechowywane w plikach xml. Program kliencki używa tych plików xml, aby uzyskać informacje o polach przechowywanych w obiekcie maszyny. Następnie używa refleksji na obiekcie maszyny, aby uzyskać dostęp do pól obiektu.

Uważam, że jest to uciążliwe i powolne. Czy istnieją jakieś wzorce lub metody tego rodzaju rzeczy?

+0

Czy przyjrzałeś się Managed Extensibility Framework (MEF)? http://mef.codeplex.com/ http://msdn.microsoft.com/en-us/library/dd460648.aspx – spender

+0

Słyszałem o tym i mam krótkie pojęcie o jego użyciu. Chodzi o to, że jestem nowy w programowaniu i chcę wdrożyć rozwiązanie, które jest łatwo przenośne na inne języki i systemy. Ponadto, chcę naprawdę nauczyć się wdrażać te złożone systemy. –

+0

Implementacja go w języku C# czyni go przenośnym dla innych systemów, ponieważ istnieje Mono, który jest portem platformy .Net działającym na Linuksie i innych platformach. Nie musiałbym martwić się, że stanie się tak ogólny, że szybko przejdzie do innych języków. Każdy język i platforma ma swój własny zestaw idiomów i najlepszych praktyk, a coś, co działa dobrze w jednym, może nie działać dobrze w innym. –

Odpowiedz

3

rozwiązanie, które przyszło mi do głowy, gdy czytam było to wykorzystanie wbudowanej obsługi Attributes w języku C#. Atrybut to sposób oznaczania właściwości, pola, metody, klasy itp. Za pomocą dodatkowych metadanych, które są następnie używane przez inną klasę, na przykład podczas Serialization. Zobaczysz to tam najczęściej.

Miałem aplikację, którą budowałem, która była potrzebna do pobrania kolekcji obiektów IEnumerable i wysłania niektórych danych do pliku na podstawie wybranych przez użytkownika opcji. Stworzyłem klasę atrybutów, dzięki której mogłem czytać wybory poprzez refleksję i postępować zgodnie z poleceniami.Pokażę wam przykład:

Pierwsza klasa atrybut:

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

Dzięki tej klasy zdefiniowanej jak więc mogłam ozdobić swoje właściwości klasy dane tak (rzeczywiste właściwości zmienione tak, aby nie zgubić żargon firma):

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

Tak więc w mojej rutyny eksportowego, zamiast sztywnego kodowania nazw właściwości, które są zmienne, lub przechodząc złożoną strukturę danych, wokół której zawarte informacje, na których polach, aby pokazać lub ukryć i co to było za rozkaz, ja wystarczy uruchomić poniższy kod, używając odbicia, aby zapętlić właściwości i wyprowadzić ich wartości, do pliku CSV w tym przypadku.

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

Kod dla struktury OrderedProperties jest tutaj:

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

Jak widać, logika, aby wyodrębnić wartości nieruchomości jest całkowicie nieświadomy struktury klasy. Wystarczy tylko znaleźć właściwości, które są ozdobione atrybutem, który stworzyłem, i użyć go do sterowania przetwarzaniem.

Mam nadzieję, że to wszystko ma sens, a jeśli potrzebujesz więcej pomocy lub wyjaśnień, proszę zapytać.

+0

Generujesz kod, nie wiedząc, jakie są właściwości obiektu, który jest do Ciebie wysyłany. Aby użyć rozwiązania w moim programie, muszę zmienić moduł generowania kodu, aby uwzględnić te atrybuty w plikach .cs, które generuję w locie. Wdroży to na razie. Dzięki. Czy znasz jednak inne metody robienia tego samego w dużo mniejszym stopniu. Czy kompilator nie robi tego, co robię, ale nieco bardziej wewnętrznie? Wątpię, czy to też wykorzystuje refleksję. Czy mam rację?? –

+1

Tak, to byłoby poprawne. Ale kompromis to znacznie prostszy zestaw przetwarzania na końcu. Pomyśl o atrybutach jako możliwych do zestawienia w stos metadanych dla twoich pól i metod.Tak długo, jak wiesz, jakie atrybuty można oczekiwać, możesz robić swoje mungowanie danych i wyświetlać, mając bardzo mało informacji o rzeczywistych obiektach zwróconych do ciebie. [Również wartości atrybutów można ustawić w czasie wykonywania, jeśli potrzebujesz.] (Http://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime) –

+0

Czy wiesz, jak wdrożyć powyższe rozwiązanie w c/C++ ?? A może dokumentacja odnosząca się do tego, co zrobiłeś? Tak bardzo nalegam na c/C++, ponieważ kodowanie w tych językach bardzo ułatwia zrozumienie działania rozwiązania na bardziej surowym poziomie. –

2

Można również pobrać ZeroMQ, które jest lekkim oprogramowaniem MQ, umożliwiło komunikację pomiędzy aplikacjami. ZeroMQ zawiera tylko 1 dll i można go osadzić w dowolnej aplikacji.

ZeroMQ ma wszelkiego rodzaju klienta, to C, C++, .NET, Java, Python, Ruby, i może działać w systemach Windows/Linux/OSX ..

+0

Czy ZeroMQ nie jest bardziej odpowiedni dla aplikacji internetowych? Moja aplikacja to aplikacja na komputer. –

+3

nie, nadaje się do aplikacji, ale nie do sieci, jest osadzony. –

+0

Ok. Wygląda na to, że używanie gniazd będzie równie intensywne, jak korzystanie z refleksji. –

Powiązane problemy