Динамический вызов методов C# на основе данных из базы данных

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

Можно ли вызвать определенный метод на С# в зависимости от того, что хранится в базе данных? Так что, если база данных говорит, расчет должен выполнять стандартное отклонение. Когда мы получим эту информацию из базы данных, можно ли тогда вызвать метод стандартного отклонения, который будет у нас в C#?

Я надеюсь, что это ясно.


person Darren Young    schedule 04.03.2011    source источник
comment
используйте Reflection , есть много примеров   -  person Stecya    schedule 04.03.2011
comment
вы могли бы закодировать каждый метод как целое число и сохранить его в БД, а затем выполнить переключение на это целое число, вызывая соответствующий метод в каждом случае?   -  person TimCodes.NET    schedule 04.03.2011
comment
Можете ли вы объяснить это более четко, потому что из того, что вы написали, я предлагаю вам просто подключиться к БД из вашего приложения C #, а затем указать некоторые условия относительно того, какой метод следует вызывать в какой ситуации, и это все. А может, вы хотите чего-то другого?   -  person Tobiasz    schedule 04.03.2011
comment
Остерегайтесь эффекта внутренней платформы.   -  person Stephen Cleary    schedule 04.03.2011


Ответы (6)


Учитывая небольшое/известное количество операций, которые будут выполняться с вашими данными, я бы предпочел кодировать эти операции вручную на основе данных, извлеченных из базы данных. Для расширяемости/обслуживаемости лучше всего создать для этого правильный дизайн вместо использования простого оператора switch. Думаю, вам подойдет шаблон стратегии.

Как уже говорилось, вы можете использовать отражение для вызова методов, указанных в базе данных. Проблема с этим подходом заключается в том, что данные в вашей базе данных тесно связаны с сигнатурами методов. Это менее удобно в сопровождении, чем первый подход, но обеспечивает большую расширяемость с минимальными корректировками кода. Еще одним недостатком является использование MethodInfo.Invoke() довольно медленно.

Если вы предпочитаете отражение, но считаете Invoke() подход слишком медленным, я могу порекомендовать эта статья Джона Скита, в которой объясняется, как преобразовать MethodInfo в экземпляр делегата. Это дает значительный прирост скорости. Недавно я написал для этого общую реализацию с использованием деревьев выражений.

В общем, похоже, что вариант 1 по-прежнему лучше всего подходит для ваших целей.

person Steven Jeuris    schedule 04.03.2011

Да, это возможно; это называется reflection и является стандартной функцией C#. В Интернете существует множество учебных пособий; вот довольно простой пример кода:

using System;
using System.Reflection;

class CallMethodByName
{
   string name;

   CallMethodByName (string name)
   {
      this.name = name;
   }

   public void DisplayName()      // method to call by name
   {
      Console.WriteLine (name);   // prove we called it
   }

   static void Main()
   {
      // Instantiate this class
      CallMethodByName cmbn = new CallMethodByName ("CSO");

      // Get the desired method by name: DisplayName
      MethodInfo methodInfo = 
         typeof (CallMethodByName).GetMethod ("DisplayName");

      // Use the instance to call the method without arguments
      methodInfo.Invoke (cmbn, null);
   }
}

http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

person Andrew Arnold    schedule 04.03.2011

Вы можете хранить операции в БД и использовать Microsoft.CSharp.CSharpCodeProvider для компилировать код на лету.

См. пример здесь: Выполнение кода во время выполнения

person acoolaum    schedule 04.03.2011

Да, вы можете сделать это с помощью Reflection. Вы можете написать класс, содержащий все операции, которые может выполнять пользователь, а затем динамически вызывать его методы.

public static class UserOperations
{
    public static decimal Average(IEnumerable<decimal> source)
    {
        return source.Average();
    }

    // Other methods
}


class Program
{
    static void Main(string[] args)
    {
        // The operation retrieved from the db
        string operation = "Average";
        // The items on which the operations should be performed
        decimal[] items = { 22m, 55m, 77m };

        object result = typeof(UserOperations).GetMethod(operation).Invoke(null, new object[] { items });
        Console.WriteLine(result);
        Console.ReadLine();
    }
}
person as-cii    schedule 04.03.2011


Вы можете использовать оператор switch в C# для выполнения нужной операции в зависимости от значения поля вашей записи (или скаляра), поступающего из базы данных. Это нормально, если у вас небольшое/ограниченное количество поддерживаемых операций, в противном случае, конечно, вы могли бы использовать reflection и класс MethodInfo для вызова метода-члена по "строковому имени" в определенном классе.

person Davide Piras    schedule 04.03.2011
comment
Я считаю, что перечисление (1-й вариант) намного быстрее и безопаснее. Что помешает кому-то поместить File.Delete() или другие неприятные имена методов в БД? - person jonathanpeppers; 04.03.2011
comment
Я согласен, я не думал о компиляции кода во время выполнения как о втором пункте, а имел в виду имя метода CalculationEngine в db. - person Davide Piras; 04.03.2011