2011-08-11

Ustalanie modyfikatora właściwości i metod

Metody i własciwości mogą być oznaczone słowami kluczowymi virtual, override, abstract. Jak wykorzystując refleksję dobrać się do tych danych ?

Nie jest to niestety takie proste. Dla metod mamy dostępne właściwości MethodInfo.IsVirtual, MethodInfo.IsAbstract.

Informacje o właściwościach są bardzo ubogie. Całe wnioskowanie musimy przeprowadzić w oparciu o metody PropertyInfo.GetGetMethod i PropertyInfo.GetSetMethod do których dostęp możemy też uzyskać poprzez PropertyInfo.GetAccessors. Wszystkie trzy metody mają przeładowaną wersję za pomocą których dobieramy się do metod niepublicznych. Tak więc analiza właściwości sprowadza się do analizy jednej z jej metod: getter-a albo setter-a. Nie trzeba analizować obu gdyż modyfikatory typu virtual, override, abstract są nakładane na właściwość.

Do ustalenia metody bazowej służy MethodInfo.GetBaseDefinition. W przypadku braku takowej funkcja nie zwraca null tylko samą siebie.

Do ustalenia typu w którym metoda została zdefiniowana służy MethidInfo.DeclaringType. Jest jeszcze MethidInfo.ReflectedType, który zwraca typ z którego dana metoda została pobrana. Np. jeśli jest to metoda publiczna zdefiniowana w klasie bazowej A, a pobrana z klasy podrzędnej B to te dwie wartości będą różne. Co więcej porównanie metod da inne wyniki.

Całość ogólnie tworzy mętny obraz. Sam nie wiem czy podane niżej rozwiązanie obejmuje wszystkie przypadki i czy nie ma jakiś wyjątków. Cała refleksja w C# jest potężna, ale jak w nią wnikamy pojawia się mnóstwo problemów. Brakuje podanych niżej metod. Metod na porównanie czy elementy są takie same, niezależnie od różnicy ReflectedType, brakuje rozbudowanej PropertyInfo, tak by nie trzeba było analizować jej metody getter-a i setter-a. Bardzo trudno ustalić, że metoda interfejsu została zadeklarowana bez użycia virtual. Bardzo trudno ustalić czy metoda została zadeklarowana przy pomocy new. Nie da się w żaden sposób powiązać właściwości automatycznej z polem prywatnym. I pewnie jeszcze wiele innych.

Moja wersja metod, która na obecny czas działają:
/// 
/// With virtual keyword. Also includes interface implementations even without 
/// virtual keyword.
/// 
/// /// 
public static bool IsVirtual(this MethodInfo a_mi)
{
    return a_mi.IsVirtual && !a_mi.IsAbstract && !a_mi.IsOverriden();
}

/// 
/// With abstract keyword.
/// 
/// /// 
public static bool IsAbstract(this MethodInfo a_mi)
{
    return a_mi.IsAbstract;
}

/// 
/// With override keyword.
/// 
/// /// 
public static bool IsOverriden(this MethodInfo a_mi)
{
    return a_mi.DeclaringType != a_mi.GetBaseDefinition().DeclaringType;

}

/// 
/// With virtual keyword. Also includes interface implementations 
/// even without virtual keyword.
/// 
/// /// 
public static bool IsVirtual(this PropertyInfo a_pi)
{
    if (a_pi.GetAccessors(true).Length == 0)
        return false;

    return a_pi.GetAccessors(true)[0].IsVirtual();
}

/// 
/// With abstract keyword.
/// 
/// /// 
public static bool IsAbstract(this PropertyInfo a_pi)
{
    if (a_pi.GetAccessors(true).Length == 0)
        return false;
    return a_pi.GetAccessors(true)[0].IsAbstract();
}

/// 
/// With override keyword.
/// 
/// /// 
public static bool IsOverriden(this PropertyInfo a_pi)
{
    if (a_pi.GetAccessors(true).Length == 0)
        return false;

    return a_pi.GetAccessors(true)[0].IsOverriden();
}

Brak komentarzy:

Prześlij komentarz