Delegate.DynamicInvoke слишком медленный, как изменить вызов на Invoke? - PullRequest
1 голос
/ 13 декабря 2010

Я читал, что должен создавать и повторно использовать делегаты, чтобы получить значение свойства объекта.

Я использую этот код для создания Делегата

    var objParm = Expression.Parameter(property.DeclaringType, "o");

    Type delegateType = typeof(Func<,>).MakeGenericType(property.DeclaringType, property.PropertyType);

    var lambda = Expression.Lambda(delegateType, Expression.Property(objParm, property.Name), objParm);

    return lambda.Compile()

Теперь я нахожу способ использовать делегата только при вызове «DynamicInvoke».

Теперь я хочу изменить вызов на «вызывать» из соображений производительности.

Я пытался

Delegate.Method.Invoke(invokedObject, null);

Но после звонка я получаю исключение

MethodInfo must be a RuntimeMethodInfo.

У меня есть класс кэша для каждого свойства, где я могу хранить динамически созданный делегат.

Что мне делать, чтобы я мог использовать "нормальные" вызовы?

Большое спасибо.

Ответы [ 2 ]

6 голосов
/ 13 декабря 2010

Вместо этого вам нужно будет выдать делегат Func<object,object> и при необходимости привести его внутри лямбды и при получении результата.Если вы не знаете тип делегата во время компиляции, вы не можете вызвать его напрямую, так как не знаете, какой тип аргументов он принимает и какой будет тип возвращаемого значения.

Также обратите вниманиечто вы можете просто создать делегата около property.GetGetMethod() - здесь нет причин для компиляции вашего собственного метода.Просто используйте метод получения свойства.

0 голосов
/ 13 декабря 2010

Я создал класс, который я использую, когда мне нужно получить доступ к свойствам, используя их имя в качестве текста. Класс кэширует все свойства для класса.

Использование:

PropertyWrapper<User> wrapper = new PropertyWrapper<User>();
wrapper.SetValue("FirstName", "arne");
int age = (int)wrapper.GetValue("Age");

Класс

public class PropertyWrapper<T>
{
    private Dictionary<string, Methods> _properties = new Dictionary<string, Methods>();
    private class Methods
    {
        public MethodBase Get { get; set; }
        public MethodBase Set { get; set; }
    }

    public PropertyWrapper()
    {
        foreach (var item in typeof(T).GetProperties())
        {
            if (!item.CanRead && !item.CanWrite)
                continue;

            var mappings = new Methods();
            if (item.CanRead)
                mappings.Get = item.GetGetMethod();
            if (item.CanWrite)
                mappings.Set = item.GetSetMethod();

            _properties.Add(item.Name, mappings);
        }
    }

    public object GetValue(T instance, string name)
    {
        Methods mappings;
        if (_properties.TryGetValue(name, out mappings) && mappings.Get != null)
            return mappings.Get.Invoke(instance, null);

        throw new MappingException("Specified property cannot be read", typeof(T), name);
    }

    public void SetValue(T instance, string name, object value)
    {
        Methods mappings;
        if (_properties.TryGetValue(name, out mappings) && mappings.Set != null)
        {
            mappings.Set.Invoke(instance, new[] { value });
            return;
        }

        throw new MappingException("Specified property cannot be written.", typeof(T), name);
    }
}

public class MappingException : Exception
{
    public MappingException(string errMsg, Type type, string propertyName) 
        : base(errMsg)
    {
        ReflectedType = type;
        PropertyName = propertyName;
    }

    public Type ReflectedType { get; private set; }
    public string PropertyName { get; private set; } 
}
...