Задача такая: по имени функции (математической) получить результат ее вычисления. Самый простой вариант такой:
public class CallFunc1
{
/// <summary>
/// Вызываем функцию по имени
/// </summary>
public double GetFuncValue(string funcName, double arg)
{
switch (funcName.ToUpper())
{
case "SIN": return Math.Sin(arg);
case "COS": return Math.Cos(arg);
case "TAN": return Math.Tan(arg);
case "SQRT": return Math.Sqrt(arg);
}
throw new ArgumentException("Такой функции нет в списке зарегистрированных функций", funcName);
}
}
Но тут мы вспоминаем, что квадратный корень нельзя вычислять от отрицательного значения и добавляем еще код:
case "SQRT":
if (arg < 0)
throw new ArgumentException("Попытка вычислить квадратный корень от отрицательного числа", "arg");
return Math.Sqrt(arg);
Потом появляются еще функции и свои проверки… В результате метод GetFuncValue напоминает сборную солянку. А хотелось бы как-то попроще и покрасивее сделать.
С помощью делегатов можно сделать так. Описываем делегат, имеющий сигнатуру метода с одним параметром:
// Делегат- математический метод
public delegate double MathFunction(double arg);
А теперь описываем словарь соответствия названий и делегатов таких методов:
// Список функций
private Dictionary<string, MathFunction> funcList;
Инициализировать его нужно будет в конструкторе:
/// <summary>
/// Конструктор
/// </summary>
public CallFunc1()
{
// Создаем список функций
funcList = new Dictionary<string, MathFunction>();
funcList.Add("SIN", delegate(double arg) {
return Math.Sin(arg);
});
funcList.Add("COS", delegate(double arg)
{
return Math.Cos(arg);
});
funcList.Add("TAN", delegate(double arg)
{
return Math.Tan(arg);
});
funcList.Add("SQRT", delegate(double arg)
{
if (arg < 0)
throw new ArgumentException("Попытка вычислить квадратный корень от отрицательного числа", "arg");
return Math.Sqrt(arg);
});
}
Обратите внимание, что реализация делегата сделана прямо “по месту” (это называется анонимными методами – методами без имени).
А с помощью LINQ вызов станет совсем простым делом:
public double GetFuncValue(string funcName, double arg)
{
// Ищем нужную функцию в списке
var func = funcList.Where(f => f.Key == funcName).Select(f => f.Value).FirstOrDefault();
// Не нашли - генерируем исключение
if (func == null)
throw new ArgumentException("Такой функции нет в списке зарегистрированных функций", funcName);
// Нашли - вызываем эту функцию
return func(arg);
}
Теперь каждое имя функции связанно со своей реализацией и своими ограничениями.
1 comment:
Для доступа к словарю тут LINQ не нужен. Можно просто через []. Это просто для примера.
Post a Comment