Как мне установить значение поля, которое является универсальным интерфейсом через отражение? - PullRequest
0 голосов
/ 12 февраля 2019

Я хочу иметь возможность использовать рефлексию для получения члена класса, скажем, типа IList, и я хочу создать для него делегат, чтобы я меньше платил за рефлексию.Все это так, что в последнее время я могу вызвать делегата, передав свой экземпляр и новый список.C # дает мне недопустимые исключения приведения каждый раз, когда я пытаюсь это сделать.Я что-то упустил из-за дженериков?

Я попытался использовать поля интерфейса без обобщения, и они, кажется, работают просто отлично.Кажется, я сталкиваюсь с проблемой только при использовании дженериков.Я также попытался использовать Convert.ChangeType для преобразования своего ввода в желаемый тип, и я получаю ошибки о том, что List <> не реализует IConvertible.Если я смогу установить значение типа IList <> из конкретного List <> с помощью отражения, я буду счастлив:)

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

public class MyObject
{
    public IList<int> MyField;
}

public class ReflectionPerfTesting
{

    public void Run()
    {
        var testObject = new MyObject();
        var field = testObject.GetType().GetField("MyField", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        InvokeUsingReflection(field, testObject);
    }

    private void InvokeUsingReflection(FieldInfo fieldInfo, object testObject)
    {
        var fieldType = fieldInfo.FieldType;
        var sourceType = fieldInfo.DeclaringType;

        // ZAS: create value parameter
        var valueParam = Expression.Parameter(fieldType);

        // ZAS: create targetParameter
        var sourceParam = Expression.Parameter(sourceType);

        var field = Expression.Field(sourceParam, fieldInfo);
        var returnExpression = (Expression)Expression.Assign(field, valueParam);
        if (!fieldType.IsClass)
        {
            returnExpression = Expression.Convert(returnExpression, fieldType);
        }

        // ZAS: create generic delegate from definition
        var delegateType = typeof(Action<,>);
        var genericType = delegateType.MakeGenericType(sourceType, fieldType);

        // ZAS: Create lambda for faster access to setter using reflection. This is meant to be cached!
        var lambdaExpression = Expression.Lambda(genericType, returnExpression, sourceParam, valueParam);
        var lambda = lambdaExpression.Compile();
        var lambdaInvokeMethod = lambda.GetType().GetMethod("Invoke");

        var list = new List<int>();
        lambdaInvokeMethod.Invoke(testObject, new object[] { list });
    }

}

Ожидаемые результаты для меня, чтобы я смог кешировать "установщик" всвойство и поддержка, устанавливающие значение любого типа, включая обобщенные и интерфейсы.Мой текущий результат заключается в том, что установка значений любого типа ЗАПРЕЩАЕТСЯ при наличии обобщений ... поэтому я должен что-то делать неправильно.

1 Ответ

0 голосов
/ 12 февраля 2019

Ваш лямбда-вызов неверен.Вы должны вызвать метод Invoke для лямбда-объекта, передавая цель, а также аргументы.

Если вы исправите вызов, вы получите желаемый результат:

testObject.Dump();

var list = new List<int>();
lambdaInvokeMethod.Invoke(lambda, new object[] { testObject, list });

testObject.Dump();

Dumping object(MyObject)
 MyField  : null
Dumping object(MyObject)
 MyField  : []

см .: https://dotnetfiddle.net/FZN3iX

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...