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ć.
Czy przyjrzałeś się Managed Extensibility Framework (MEF)? http://mef.codeplex.com/ http://msdn.microsoft.com/en-us/library/dd460648.aspx – spender
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. –
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. –