CreateDelegate с неизвестными типами

Я пытаюсь создать Делегата к чтению/записи свойств неизвестного типа класса во времени выполнения.

У меня есть универсальный класс Main и метод, который похож на это:

Delegate.CreateDelegate(typeof(Func), get)

где get a MethodInfo из свойства, которое должно быть считано. Проблема - это, когда свойство возвращается int (Я предполагаю, что это происходит для типов значения), вышеупомянутый код бросает ArgumentException, потому что метод не может быть связан. В случае строки это работает хорошо.

Для решения проблемы, я изменил код так, чтобы соответствующий тип Делегата был сгенерирован при помощи MakeGenericType. Таким образом, теперь код:

Type func = typeof(Func<,>);
Type generic = func.MakeGenericType(typeof(T), get.ReturnType);
var result = Delegate.CreateDelegate(generic, get)

Проблема теперь состоит в том что созданный экземпляр делегата generic таким образом, я должен использовать DynamicInvoke который был бы столь же медленным как использование чистого отражения для чтения поля.

Таким образом, мой вопрос состоит в том, почему это - первый отрывок сбоев кода с типами значения. Согласно MSDN это должно работать, поскольку это говорит это

Тип возврата делегата совместим с типом возврата метода, если тип возврата метода более строг, чем тип возврата делегата

и как выполнить делегата во втором отрывке так, чтобы это было быстрее, чем отражение.

Спасибо.

11
задан Giorgi 22 March 2010 в 08:42
поделиться

4 ответа

Вот один из способов решения вашей проблемы. Создайте общий метод:

public static Func<T, object> MakeDelegate<U>(MethodInfo @get)
{
    var f = (Func<T, U>)Delegate.CreateDelegate(typeof(Func<T, U>), @get);
    return t => f(t);
}

Таким образом, компилятор C# позаботится о вставке необходимых боксов (если таковые имеются) для преобразования f(t) (типа U) в object. Теперь вы можете использовать отражение, чтобы вызвать этот метод MakeDelegate с U, установленным в @get.ReturnType, и то, что вы получите обратно, будет Func, который можно вызвать без необходимости прибегать к использованию DynamicInvoke.

10
ответ дан 3 December 2019 в 08:03
поделиться

Вызов завершился неудачно, потому что вам нужен объект, а не тип значения (например, INT) - очевидно, Func не является Func - это не будет работать с любым vt, таким как double или bool. Либо верните упакованный Int (или все, что у вас есть). или (возможно, лучше) использовать API-интерфейс отражения.

Используя классы испускания отражения, Вы можете создавать динамические методы и сохранять их как делегаты, или создавать динамические делегаты и сохранять их в какой-то своей структуре. Вы можете сделать это только один раз (возможно, один раз за время выполнения), сохранить его в каком-либо Dict и вызывать при необходимости.

надеюсь, что это поможет. люк

2
ответ дан 3 December 2019 в 08:03
поделиться

Ваш исходный код может работать только для ссылочных типов. Вот почему строка не была проблемой, она напрямую происходит от System.Object. То, что тип значения является производным от ValueType и Object, является хорошей иллюзией на бумаге, но на самом деле требует кода. Компилятор C # автоматически генерирует этот код, для этого требуется преобразование упаковки. Это та часть, которая здесь отсутствует, нет преобразования времени выполнения из int в объект без кода операции BOX .

Вы можете получить этот код операции в своем коде, но вам придется использовать System.Reflection.Emit.

Прежде чем идти туда, сначала проверьте, не слишком ли медленно то, что у вас сейчас есть. Расходы на отражение - это извлечение метаданных из сборки. Это было сделано при создании делегата, после этого информация о типе кэшируется.

3
ответ дан 3 December 2019 в 08:03
поделиться

Можно ли ограничить общий метод только работой со ссылочными типами и создать другой, чтобы он работал только с типами значений, и решить, какие функции использовать соответственно?

0
ответ дан 3 December 2019 в 08:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: