AnnulusGames/LucidEditor

Reflection改善の提案

Akeit0 opened this issue · 2 comments

ReflectionUtil.cs ではターゲットのオブジェクトに対してキャッシュしていますが、型に対してキャッシュする方がよいと思います。

private static Dictionary<(Type, string), Func<object,object>> cacheGetter;

if (cacheGetter.TryGetValue((type, name),out var f)){
              return f(target);
}

public static Func<object, object> CreateGetter(FieldInfo fieldInfo) {
    if (fieldInfo.IsStatic) {
        Expression body = Expression.Convert(Expression.MakeMemberAccess(null, fieldInfo), typeof(object));
        var lambda = Expression.Lambda<Func<object>>(body).Compile();
        return _=>lambda();
    }
    if (fieldInfo.DeclaringType != null) {
        var objParam = Expression.Parameter(typeof(object), "obj");
        var tParam= Expression.Convert(objParam, fieldInfo.DeclaringType);
        Expression body = Expression.Convert(Expression.MakeMemberAccess(tParam, fieldInfo), typeof(object));
        return Expression.Lambda<Func<object, object>>(body,objParam).Compile();
    }
    return null;
}
public static Func<object, object> CreateGetter(PropertyInfo propertyInfo) {
    if (propertyInfo.GetGetMethod(true).IsStatic) {
        Expression body = Expression.Convert(Expression.MakeMemberAccess(null, propertyInfo), typeof(object));
        var lambda = Expression.Lambda<Func<object>>(body).Compile();
        return _=>lambda();
    }
    if (propertyInfo.DeclaringType != null) {
        var objParam = Expression.Parameter(typeof(object), "obj");
        var tParam= Expression.Convert(objParam, propertyInfo.DeclaringType);
        Expression body = Expression.Convert(Expression.MakeMemberAccess(tParam, propertyInfo), typeof(object));
        return Expression.Lambda<Func<object, object>>(body,objParam).Compile();
    }
    return null;
}

いただいたコードを参考にReflectionUtilのコードを修正しました。ありがとうございます!

if (!cacheGetPropertyValue.ContainsKey((type, name)))
{
    //キャッシュ作る
}
if (cacheGetPropertyValue[(type, name)] == null) return null;
else return cacheGetPropertyValue[(type, name)].Invoke(target);

と書くと何回も検索していて無駄なので、

if (!cacheGetPropertyValue.TryGetValue((type, name), out var f )){
         PropertyInfo info = type.GetProperty(name, bindingAttr);
        cacheGetPropertyValue.Add((type, name),f=CreateGetter(info) );
}
return f?.Invoke(target)

と書くとスマートかつ検索が一回になります(正直ほかのエディタ処理の重さからしたら誤差)。out は外側で定義したものと同じ扱いなのでこう書けます。
またnull条件演算子はgetterがnullだったらnullを返してくれるので、おすすめです。

こんな書き方があるんだな程度で時間あるときに対応してみてください。