C# 在整个应用程序中传递运行时参数

C# 在整个应用程序中传递运行时参数,c#,oop,C#,Oop,我有一个遗留的C#库(一组相互关联的算法),其中有一个全局god对象,它被传递给所有类。这个god对象(简单地称为Manager:D)有一个Parameters成员和一个ObjectCollection成员(以及许多其他成员) 我无法测试算法,因为所有操作都将管理器视为依赖项,而初始化意味着我必须初始化所有操作。所以我想重构这个设计 参数中有100多个字段,这些值控制不同的算法。ObjectCollection具有引擎整体执行所需的实体,这些实体按Id、名称等存储 以下是我想到但不满意的方法:

我有一个遗留的C#库(一组相互关联的算法),其中有一个全局god对象,它被传递给所有类。这个god对象(简单地称为Manager:D)有一个Parameters成员和一个ObjectCollection成员(以及许多其他成员)

我无法测试算法,因为所有操作都将管理器视为依赖项,而初始化意味着我必须初始化所有操作。所以我想重构这个设计

参数中有100多个字段,这些值控制不同的算法。ObjectCollection具有引擎整体执行所需的实体,这些实体按Id、名称等存储

以下是我想到但不满意的方法:

  • 传递参数和ObjectCollection(或IParameters和IObjectCollection)而不是管理器,但我认为这解决不了任何问题。我不知道算法将依赖哪些参数

  • 将参数类拆分为较小的参数类也很困难,因为一个参数可能会影响许多算法,因此很难进行逻辑分离。加上每种算法的依赖性可能最终会很多

  • 类似的单例模式通常用于记录器,但这也是不可测试的

  • 一些参数控制算法逻辑,一些参数只是算法所需。我正在考虑将每个算法作为一个单独的类来实现一个接口,并在应用程序开始时,根据参数决定实例化哪个算法。我可能会把当前的一组算法类拆分成更多的类,我担心最终会使它更加复杂,并失去算法的结构


  • 有没有标准的方法来处理这个问题,或者仅仅是将大型类拆分为小型类,并通过构造函数传递依赖项,这是唯一的一般建议?

    对于参数,我会选择如下方式:

    public class Parameters
    {
        public int MyProperty1 { get; set; }
        public int MyProperty2 { get; set; }
        public int MyProperty3 { get; set; }
    }
    
    public class AlgorithmParameters1
    {
        private Parameters parameters;
    
        public int MyProperty1 { get { return parameters.MyProperty1; } }
    
        public int MyProperty3 { get { return parameters.MyProperty3; } }
    
        public AlgorithmParameters1(Parameters parameters)
        {
            this.parameters = parameters;
        }
    }
    
    public class Algorithm1
    {
        public void Run(AlgorithmParameters1 parameters)
        {
            //Access only MyProperty1 and MyProperty3...
        }
    }
    
    用法如下所示:

    var parameters = new Parameters()
    {
        MyProperty1 = 4,
        MyProperty2 = 5,
        MyProperty3 = 6,
    };
    
    new Algorithm1().Run(new AlgorithmParameters1(parameters));
    

    顺便说一句,我不明白控制算法的参数和算法所需的参数之间有什么区别。你说的控制是指它们被用来决定采用哪种算法?

    为了让你自己迈出一小步,我从一个算法开始,确定它需要的参数。然后可以在接口中公开这些内容,以便

    public interface IAmTheParametersForAlgorithm1 
    {
      int OneThing {get;}
      int AnotherThing {get;}
    }
    
    然后,您可以修改
    Manager
    ,使其实现该接口,并在@marcel的回答中直接在Manager上公开这些参数

    现在,您可以使用一个非常小的模拟或自分流来测试算法1,因为您不需要初始化一个巨大的管理器来运行测试。算法1不再知道它需要一个管理器对象

    public Manager : IAmTheParametersForAlgorithm1 {}
    
    public class Algorithm1 
    {
      public Algorithm1(IAmTheParametersForAlgorithm1 parameters){}
    }
    
    一点一点地,您可以继续将其扩展到每一组参数,并处理小的、特定的接口,这将允许您识别不同算法具有公共参数的位置

    public Manager : 
      IAmTheParametersForAlgorithm1, 
      IAmTheParametersForAlgorithm2, 
      IAmTheParametersForAlgorithm3, 
      IAmTheParametersForAlgorithm4 {}
    
    这还意味着,当您识别其参数不再在其接口之外被访问的算法时,您可以停止向这些算法中注入Manager,从Manager中取出参数,并创建一个只提供这些参数的新类

    public Manager : 
      IAmTheParametersForAlgorithm1, 
      IAmTheParametersForAlgorithm2, 
      IAmTheParametersForAlgorithm3, 
      IAmTheParametersForAlgorithm4 {}
    

    这意味着您可以在进行此更改的整个过程中保持应用程序的运行,如果您无法花时间进行一次巨大的突破性更改

    您是否尝试过将管理器作为公共静态变量?然后,它可以被所有班级阅读,也可以被他们编辑。谢谢你的回答。这些参数控制算法的内部工作。例如,一个名为UseStactinColCounts的参数将确定除法运算的结果是int还是double!谢谢:)