【问题标题】:Calling C# methods dynamically based on data from database根据数据库中的数据动态调用 C# 方法
【发布时间】:2011-03-04 13:02:10
【问题描述】:

我的老板让我研究计算引擎。实际上,用户将拥有一个可以执行计算的数据表。他们还将能够根据我们强制执行的某些限制构建自己的计算(构建的计算随后将存储在数据库中)

是否可以在 C# 中调用特定方法,具体取决于数据库中存储的内容?因此,如果数据库说,计算应该执行标准偏差。当我们从数据库中获取该信息时,是否可以调用我们将在 C# 中使用的标准偏差方法?

我希望这很清楚。

【问题讨论】:

  • 使用反射,例子很多
  • 您可以将每个方法编码为整数并将其存储在数据库中,然后在该整数上执行开关,在每种情况下调用相关方法?
  • 你能解释得更清楚吗,因为从你写的内容来看,我建议你从你的 C# 应用程序连接到数据库,然后就应该在哪种情况下调用哪个方法做出一些条件,仅此而已.或者也许你想要别的东西?

标签: c# dynamicmethod


【解决方案1】:

考虑到将对您的数据执行的少量/已知操作,我会选择手动编码这些操作,基于从数据库中检索到的数据。对于可扩展性/可维护性,最好为此创建适当的设计,而不是使用简单的 switch 语句。我猜Strategy pattern 会满足您的需求。

正如其他人所说,您可以使用reflection,调用数据库中指定的方法。这种方法的问题是数据库中的数据与方法签名密切相关。与第一种方法相比,这种方法的可维护性较差,但确实可以通过最少的代码调整实现出色的可扩展性。另一个缺点是使用MethodInfo.Invoke() 相当慢。

如果您选择反射,但发现Invoke() 方法太慢,我可以推荐this article by Jon Skeet,它解释了如何将 MethodInfo 转换为委托实例。这大大提高了速度。我最近为此写了a generic implementation using expression trees

总而言之,选项 1 似乎仍然是您的最佳选择。

【讨论】:

    【解决方案2】:

    是的,这是可能的;它被称为 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

    【讨论】:

      【解决方案3】:

      您可以将操作存储在 DB 中并使用 Microsoft.CSharp.CSharpCodeProvider 即时编译代码。

      在此处查看示例:Execute code at runtime

      【讨论】:

        【解决方案4】:

        是的,您可以使用反射来做到这一点。您可以编写一个包含用户可以执行的所有操作的类,然后动态调用其方法。

        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();
            }
        }
        

        【讨论】:

          【解决方案5】:

          我建议你实施策略模式 (http://www.dofactory.com/Patterns/PatternStrategy.aspx)

          您可以为所需的不同计算加载不同的策略(算法)。

          还有一个不错的帖子http://blogs.microsoft.co.il/blogs/gilf/archive/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements.aspx

          【讨论】:

            【解决方案6】:

            您可以使用 C# 中的 switch 语句来执行您想要的操作,具体取决于来自数据库的记录字段(或标量)的值。如果您支持的操作数量很少/数量有限,这是可以的,否则您当然可以使用reflection 和 MethodInfo 类在某个类上通过“字符串名称”调用成员方法。

            【讨论】:

            • 我相信枚举(第一个选项)更快更安全。什么会阻止某人将 File.Delete() 或其他讨厌的方法名称放入数据库中?
            • 我同意,我并没有考虑将运行时代码编译作为第二点,而是将 CalculationEngine 的方法名称放在数据库中。
            猜你喜欢
            • 2020-04-25
            • 2011-03-28
            • 2018-03-13
            • 2013-01-25
            • 1970-01-01
            • 1970-01-01
            • 2016-09-17
            • 2017-07-30
            • 1970-01-01
            相关资源
            最近更新 更多