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