2010-08-20 2 views
1

Я использую Reflection.Emit для создания парсера математических выражений (например, 2+2). Класс принимает выражение infix (например, 2+2), превращает его в постфиксное выражение (например, 2 2 +), а затем другой класс компилирует это постфиксное выражение в IL и создает DynamicMethod. Оттуда выражение можно оценить так, как если бы оно было создано во время компиляции с одинаковой скоростью.Вызвать метод, используя экземпляр MethodInfo в стеке, используя Reflection.Emit

Этот компилятор поддерживает неявное умножение, так что-то вроде x(2 + 2) вычисляется как x * (2 + 2)

Сейчас я пытаюсь реализовать определяемые пользователем функции (например, f(x)). Проблема возникает, когда я пытаюсь различать неявное умножение, как показано выше, и определенные пользователем функции. Например, если пользователь вводит x(5), как узнать, хотят ли они умножить x на 5 или вызвать функцию x с аргументом 5?

Чтобы решить эту проблему, в предыдущем случае компилятор вставляет в поток IL if. Он вызывает функцию, чтобы определить, определена ли функция с идентификатором x. Если есть, то он вставляет экземпляр MethodInfo в стек через переменную out и локальную.

Мой фактический вопрос заключается в возможности выполнить метод с использованием экземпляра MethodInfo в стеке, который эквивалентен по скорости вызову IlGenerator.Emit(OpCodes.Call, MethodInfo) во время компиляции?

Спасибо.

+0

Рекомендация по дизайну: Сделать умножение явным или иметь другой синтаксис вызова функции. Наличие неоднозначного синтаксиса приводит к ошибкам/трудно идентифицировать ошибки пользователя. Вы знаете, что стандартная арифметическая нотация сосет, или вы не удосужились конвертировать в постфикс, и это одна из причин :) –

ответ

1

Единственный способ, которым я это знаю, позволяет вам вызвать экземпляр MethodInfo в стеке, вызвав на нем метод Invoke. Я уверен, что вы уже знаете об этой возможности, но вы опасаетесь, что это может быть слишком медленно. Я рекомендую вам попробовать и время исполнения под стрессом. Вы можете обнаружить, что это достаточно быстро для ваших целей.

Если это не так, вам придется подумать о том, как изменить структуру вашего проекта, чтобы вы не проходили мимо MethodInfo экземпляров. Вы могли бы, например, передать управляемые указатели функций. Это те вещи, которые возвращают инструкции ldftn и ldvirtftn. Затем вы можете использовать команду calli для вызова одного из них. Вам нужно будет создать «описание сайта», которое calli ожидает в качестве операнда, используя SignatureHelper class.

+0

Большое спасибо! Хотя я не использовал точное решение здесь, это привело меня к другому способу борьбы с ним. – mgbowen

+0

@nasufara: Пожалуйста, подумайте об объяснении решения, которое вы нашли в отдельном ответе, чтобы другие могли извлечь из этого выгоду. – Timwi

Смежные вопросы