Reflection optimalizálás delegáltakkal

Szorosan követi az előző bejegyzés témáját a mostani is, újra a reflection van középpontban. Ezúttal a reflectionön keresztül megszerzett propertyk (ld. PropertyInfo) gyakori hozzáférésének optimalizálása lesz a figyelem középpontjában.

Propertyhez hozzáférni alapvetően a GetValue és a SetValue metódusokon keresztül lehet, ezeknek azonban a közös tulajdonsága, hogy lassúak. Gyakori hozzáférés esetén ez értelemszerűen problémás.

Trükközésre aránylag kevés lehetőség van, ugyanakkor egy lehetőség adott. A PropertyInfo objektumnak van kettő, GetMethod és SetMethod propertyje, egyenként egy MemberInfót, pontosabban egy MethodInfo-t adnak vissza.

Ez az osztály ugyan még mindig nagyon relfection-alapú és mint korábban mutattuk egy Invoke hívással a kívánt eredményt el is érhető. Ennél azonban – tekintve hogy optimalizálni próbálunk – a CreateDelegate metódusának meghívása. Ezzel egy kívánt típusú delegált visszakapható. Érdemes itt mondjuk nem nagyon elkalandozni, szerencsére a .NET környezetben ilyesmire általánosan használt delegáltak – a Func és az Action – tökéletesen működnek.

Egy egyszerű kódrészlet a használatukra:

public class GetSet<T, K>
{
    public Func<T, K> Getter { get; private set; }
    public Action<T, K> Setter { get; private set; }

    public Type ValueType { get; }
    public List<string> Attributes { get; } = new List<string>();

    public GetSet()
    {
        this.ValueType = typeof(K);
    }

    public GetSet(PropertyInfo info): this()
    {
        this.Init(info);
    }

    public bool Init(PropertyInfo info)
    {
        bool valid = false;

        MethodInfo setMethod = info.GetSetMethod();
        MethodInfo getMethod = info.GetGetMethod();

        if(setMethod != null && getMethod != null)
        {
            this.Setter = (Action<T, K>)Delegate.CreateDelegate(typeof(Action<T, K>), null, setMethod);
            this.Getter = (Func<T, K>)Delegate.CreateDelegate(typeof(Func<T, K>), null, getMethod);
            valid = true;
        }

        return valid;
    }
}

A generikusok közül a T a propertyInfo által leírt property t tartalmazó objektum típusa, a K maga a property típusa. Használni már nagyon egyszerű, amint sikerült léterozni a GetSet objektumunkat, már csak a Getter és Setter delegáltakra kell ráhívni:

int value = getSet.Getter(obj);
getSet.Setter(obj, value);

Ajánljuk ennek a megoldásnak a használatát? Egyértelműen nem. De ha nincs más választás, ezeket az apró trükköket bevetve könnyebbé tehetjük az életünket.