Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > вычисление произвольной функции


Автор: q65 14.5.2011, 19:34
Необходимо вычислять значения произволных функций ,которые подаются в виде строки. Можно ли это реализовать ,чтобы данная строка транслировалась в код -и создавался метод который был возвращал результат функции? 

Автор: Экскалупатор 14.5.2011, 19:40
q65, думаю что если организовать динамическую компиляцию то можно что нибудь придумать...

Автор: -Mikle- 14.5.2011, 19:53
Обратная польская нотация (запись), если тебе не требуется именно компилировать ф-ии в код.

Автор: q65 14.5.2011, 19:57
хочется реализовать без парсинга строки

Автор: -Mikle- 14.5.2011, 20:02
Как без парсинга? Какой синтаксис у формулы? Сишарповский?

Автор: q65 14.5.2011, 20:08
забыл ,что в с# необходимо указывать класс для вызова мат функций- если можно не указывать, то топик еще атуален

Автор: Экскалупатор 14.5.2011, 20:42
Код

double Calc()
        {
            return 10 * 12 / 22;
        }

возвращает результат вычисленного выражения. если ты подставишь в исходный код другую строку(файл *.cs это текстовый файл), и скомпилируешь то метод будет возвращать то что ты в него запишешь. только кажется мне что проще написать парсер, чем реализовать динамическую компиляцию, в которой все равно придется искать то место в котором нужно поменять выражение.

Автор: -Mikle- 14.5.2011, 22:08
Если все таки компиляцию, то можно так:
Код

public static class Evaluator
{
    private const string codePart1 = "using System; public static class ";
    private const string codePart2 = "_Calc_";
    private const string codePart3 = " { public static double ";
    private const string codePart4 = "Eval";
    private const string codePart5 = "() { return ";
    private const string codePart6 = "; } }";

    public static double Evaluate(string expression)
    {
        CSharpCodeProvider codeProvider = new CSharpCodeProvider();
        CompilerParameters param = new CompilerParameters { GenerateInMemory = true };
        CompilerResults result = codeProvider.CompileAssemblyFromSource(param, string.Concat(codePart1, codePart2, codePart3, codePart4, codePart5, expression, codePart6));

        if (result.Errors.HasErrors)
            throw new InvalidOperationException(string.Format("Произошла ошибка во время компиляции выражения:\r\n{0}", string.Join("\r\n", result.Errors.OfType<CompilerError>())));

        Type type = result.CompiledAssembly.GetType(codePart2);
        if (type == null)
            throw new InvalidOperationException("Непредвиденная ошибка (тип не найден).");

        return (double)type.InvokeMember(codePart4, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, null);
    }
}


используешь так:
Код

MessageBox.Show(Evaluator.Evaluate("(23+2)*2").ToString());
MessageBox.Show(Evaluator.Evaluate("Math.Sin(Math.PI) * Math.Cos(Math.PI)").ToString());


Но имей ввиду, что компиляция процесс не быстрый, так что пользуйся, только если производительность тебя устраивает. Но я бы на твоем месте сделал нотацию, тем более ,что делов там не много. Можно еще построить дерево выражений (Expression), но тоже вариант не производительный.

Автор: jonie 15.5.2011, 00:02
Цитата(-Mikle- @  14.5.2011,  22:08 Найти цитируемый пост)
Но имей ввиду, что компиляция процесс не быстрый, так что пользуйся, только если производительность тебя устраивает. Но я бы на твоем месте сделал нотацию, тем более ,что делов там не много. Можно еще построить дерево выражений (Expression), но тоже вариант не производительный. 

мало того что не быстрый, так еще и требует full trust-а... 
Можно заюзать IronPython например, или другой какой язык.. в C#5 поговаривают Compiler as Service будет из коробки

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)