Do takich zadań możemy użyć funkcjonalności z "Reflection".
W namespace System.Reflection znajdują sie klasy umożliwiające pobieranie wszelakich danych z kodu zarządzanego na podstawie "metadanych" a także manipulacje instancjami typów - jak pobieranie oraz zmiana wartości co właśnie chciałem dziś przedstawić.
Tak więc zacznę od metody "GetProperty":
PropertyInfo result = typeof(T).GetProperty(propertyName, typeof(TProperty));Powyższy kawałek kodu zwraca nam klasę "PropertyInfo" opisującą parametry publicznej właściwości o nazwie zdefiniowanej za pomocą zmiennej "propertyName" oraz typie "TProperty". Właściwość ta znajdować ma się obiekcie typu "T".
W przypadku jeżeli typ "T" nie posiada właściwości spełniającej takie kryteria metoda zwraca "null".
Aby zilustrować działanie metody "GetProperty" oraz problem, który należy rozwiązać zdefiniujmy klasy:
interface IA { int Props { get; set; } } interface IB : IA { } class A : IA { public int Props {get; set;} private int prProps { get; set; } } class B : IB { public int Props { get; set; } }Z kody wynika, że zarówno klasy jak i interfejsy mają właściwość "Props".
[TestMethod()] public void GetPropertyTest() { PropertyInfo result = typeof(A).GetProperty("Props", typeof(int)); Assert.IsNotNull(result); result = typeof(A).GetProperty("prProps", typeof(int)); Assert.IsNull(result); result = typeof(IA).GetProperty("Props", typeof(int)); Assert.IsNotNull(result); result = typeof(B).GetProperty("Props", typeof(int)); Assert.IsNotNull(result); result = typeof(IB).GetProperty("Props", typeof(int)); Assert.IsNotNull(result);//result is null!!! }Jednak test jednostkowy sprawdzający działanie "GetProperty" na zdefiniowanych typach zwraca nieoczekiwaną wartość "null" przy interfejsie "IB".
Problem wynika stąd, że właściwość "Props" w interfejsie "IB" jest właściwością dziedziczoną po "IA".
Problem można rozwiązać za pomocą funkcji, która sprawdzi wszystkie interfejsy:
public static PropertyInfo GetProperty<T, TProperty>(string propertyName) { Type type = typeof(T); PropertyInfo result = type.GetProperty(propertyName, typeof(TProperty)); if (result != null) return result; if (type.IsInterface) { foreach (Type interfaceTypes in type.GetInterfaces()) { result = interfaceTypes.GetProperty(propertyName, typeof(TProperty)); if (result != null) return result; } } return null; }Gdy już mamy funkcję znajdującą "property" dla typu, możemy skorzystać z niej pisząc metody umożliwiające pobranie wartości "GetValue" oraz jej zmianę "SetValue":
public static TProperty GetValue<T, TProperty>(T obj, string propertyName) { PropertyInfo pi = GetProperty<T, TProperty>(propertyName); if (pi != null) return (TProperty)pi.GetValue(obj, null); return default(TProperty); } public static void SetValue<T, TProperty>(T obj, string propertyName, TProperty newValue) { Type type = typeof(T); PropertyInfo pi = GetProperty<T, TProperty>(propertyName); if (pi != null) pi.SetValue(obj, newValue, null); }I to by było na razie tyle tytułem wstępu do rozległego tematu jakim jest "Reflection".
Brak komentarzy:
Prześlij komentarz