Это зависит от того, как вы хотите, чтобы пользователь программы «предоставлял разрешенные функции».
- Если пользователь выбирает функции, которые вы уже реализовали, вы можете передавать их как делегаты или деревья выражений.
- Если пользователь собирается написать свои собственные методы на C # или другом языке .NET и скомпилировать их в сборку, вы можете загрузить их с помощью Reflection.
- Если вы хотите, чтобы пользователь мог вводить исходный код C # в вашу программу, вы можете скомпилировать его с помощью CodeDom, а затем вызвать получившуюся сборку с помощью Reflection.
- Если вы хотите предоставить пользовательский язык выражений для пользователя, например, простой математический язык, затем (при условии, что вы можете проанализировать язык) вы можете использовать Reflection.Emit для генерации динамической сборки и вызывать ее, используя - как вы уже догадались - Reflection. Или вы можете построить дерево выражений из пользовательского кода и скомпилировать его с помощью LINQ - в зависимости от того, насколько вам нужна гибкость. (И если вы можете позволить себе подождать, деревья выражений в .NET 4.0 снимают многие из ограничений, которые были в 3.5, так что вы можете вообще избежать Reflection.Emit.)
- Если вы рады, что пользователь вводит выражения с использованием Python, Ruby или другого языка DLR, вы можете разместить Dynamic Language Runtime, который будет интерпретировать код пользователя для вас.
Хостинг DLR (и IronPython или IronRuby) может быть хорошим выбором здесь, потому что вы получаете хорошо протестированную среду и все оптимизации, которые обеспечивает DLR. Вот инструкции по использованию IronPython.
Добавлено в ответ на ваш вопрос производительности: DLR достаточно умен в оптимизации. Он не слепо интерпретирует исходный код каждый раз: как только он преобразует исходный код (или, в частности, данную функцию или класс) в MSIL, он будет продолжать использовать это скомпилированное представление, пока исходный код не изменится (например, функция переопределена). Так что, если пользователь продолжает использовать одну и ту же функцию, но для разных наборов данных, то, пока вы можете хранить один и тот же ScriptScope, вы должны получить приличную производительность; То же самое, если вы беспокоитесь только о том, что во время генетического алгоритма вы будете выполнять одну и ту же функцию миллионы раз. Хостинг DLR довольно прост, поэтому не составит труда сделать подтверждение концепции и оценить, соответствует ли она вашим потребностям.