Здравствуйте, возникла такая проблема.
Есть библиотека, выполняющая функции калькулятора. Ей задаются строки вида "a=5"(запомнить переменную с именем a и значение 5), "4+a"(возвратить результат 4+5) и т.д.
Необходимо сделать следующее, ввести стоку примера "apt(x,y)=aptfunc"(где apt — имя функции для запоминания, (x,y) — ее аргументы, aptfunc — имя делегата функции". Сам делегат определен в программе, вызывающей эту библиотеку:
class pr1
{
public static int apt(int x, int y)
{
return x * y;
}
}
class Program
{
public static CalcLib.CalcLib cl = new CalcLib.CalcLib();
delegate int aptdelg(int x,int y);
static void Main(string[] args)
{
aptdelg aptfunc = new aptdelg(pr1.apt);
cl["apt(x,y)"] = "aptfunc";
int result=cl["apt(3,4)"];
}
для получения результата result калькулятору отправляется строка "apt(3,4)", по которой она должна вызвать метод pr1.apt с аргументами 3 и 4.
так вот вопрос, как из библиотеки вызвать метод p1.apt с аргументами (3,4)
имея только текстовое название делегата "aptfunc", может чтото не так делаю, может нужно задавать строку так: "apt(x,y)=aptdelg", я в этом плохо понимаю...
Спасибо за ответы.
Здравствуйте, BDEsoft, Вы писали:
BDE>так вот вопрос, как из библиотеки вызвать метод p1.apt с аргументами (3,4) имея только текстовое название делегата "aptfunc", может чтото не так делаю, может нужно задавать строку так: "apt(x,y)=aptdelg", я в этом плохо понимаю...
если aptfunc локальная переменная — никак.
функцию p1.apt вызвать через рефлекшн проблем нет, зачем понадобилось ссылаться на локальный делегат — непонятно, т.е. я не вижу вероятных сценариев использования.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Здравствуйте, BDEsoft, Вы писали:
BDE>так вот вопрос, как из библиотеки вызвать метод p1.apt с аргументами (3,4) имея только текстовое название делегата "aptfunc", может чтото не так делаю, может нужно задавать строку так: "apt(x,y)=aptdelg", я в этом плохо понимаю...
BDE>Спасибо за ответы.
Ну делегат тут не удачный выбор, такие вещи делаются примерно так:
using System;
using System.Collections;
using System.Collections.Generic;
public abstract class Operation
{
public abstract int ArgumentCount { get; }
public abstract int Do(int[] arguments);
protected virtual void checkArguments(int[] arguments)
{
if (arguments.Length != ArgumentCount)
throw new ArgumentException(GetType().ToString() + " требует " + ArgumentCount.ToString() + " аргументов, но передано " + arguments.ToString() + "!");
}
}
public class AddOperation : Operation
{
public override int ArgumentCount { get { return 2; } }
public override int Do(int[] args)
{
checkArguments(args);
return args[0] + args[1];
}
}
public class SubOperation : Operation
{
public override int ArgumentCount { get { return 2; } }
public override int Do(int[] args)
{
checkArguments(args);
return args[0] - args[1];
}
}
public class AptFuncOperation : Operation
{
public override int ArgumentCount { get { return 2; } }
public override int Do(int[] args)
{
checkArguments(args);
return args[0] * args[1];
}
}
public class Calculator
{
private Stack _stack = new Stack();
private Dictionary<string, Operation> _operations = new Dictionary<string, Operation>();
public Calculator()
{
_operations["+"] = new AddOperation();
_operations["-"] = new SubOperation();
_operations["aptfunc"] = new AptFuncOperation();
}
public void PushOperand(int value)
{
_stack.Push(value);
}
public void PushOperation(string name)
{
if (!_operations.ContainsKey(name))
throw new ArgumentException("Неизвестная операция: " + name);
_stack.Push(_operations[name]);
}
public int Calculate()
{
if (_stack.Count < 1)
throw new InvalidOperationException("Нет данных для вычислений");
object val = _stack.Pop();
Operation op = val as Operation;
if (op == null)
return (int)val;
int argCount = op.ArgumentCount;
int[] args = new int[op.ArgumentCount];
for (int i = 0; i < args.Length; i++)
{
if (_stack.Count < argCount)
throw new ArgumentException("Недостаточно аргументов для операции " + op.GetType().ToString());
if (_stack.Peek() is Operation)
args[i] = Calculate();
else
args[i] = (int)_stack.Pop();
argCount--;
}
return op.Do(args);
}
}
// Тестируем то что получилось :)
class Program
{
static void Main()
{
Calculator calc = new Calculator();
// Вычисляем "aptfunc(2, 2)" [ aptfunc(2, 2) = 4 ]
calc.PushOperand(2);
calc.PushOperand(2);
calc.PushOperation("aptfunc");
Console.WriteLine("aptfunc(2, 2) = {0}", calc.Calculate());
// Вычисляем "aptfunc(30-5, 3+2)" [ aptfunc(30-5, 3+2) = aptfunc(25, 5) = 125 ]
calc.PushOperand(2);
calc.PushOperand(3);
calc.PushOperation("+");
calc.PushOperand(5);
calc.PushOperand(30);
calc.PushOperation("-");
calc.PushOperation("aptfunc");
Console.WriteLine("aptfunc(30-5, 3+2) = {0}", calc.Calculate());
}
}
Тебе остается дописать токенайзер и транслятор в обратную польскую запись, с этим думаю справишься. Ну и если надо с разными типами данных работать, то напиши свой класс представляющий значение и замени int на этот класс...
Вот собственно и всё

... << RSDN@Home 1.2.0 alpha rev. 676>>