将配置值作为参数传递给实例方法C#

时间:2020-03-03 18:05:12

标签: c#

重构代码时,我经常遇到这个问题。假设我有一个基类,并且阅读了一些配置参数并将其填充到这样的属性中

public BaseClass()
{
   _property1 = ConfigurationManager.AppSettings["AppSetting1"];
   _property2 = ConfigurationManager.AppSettings["AppSetting2"];
   _property3 = ConfigurationManager.AppSettings["AppSetting3"];
}

然后我在另一个这样的类中调用一个方法

OtherClass otherClass = new OtherClass();
var foo = otherClass.SomeMethod(_property1, _property2, _property3);

这样做更好吗?如果我仅需要OtherClass类内部的AppSettings值怎么办?然后我就可以将它们加载为私有道具,并在构造函数中对其进行初始化,而引用类/调用者则不必担心设置。

public OtherClass()
{
   _property1 = ConfigurationManager.AppSettings["AppSetting1"];
   _property2 = ConfigurationManager.AppSettings["AppSetting2"];
   _property3 = ConfigurationManager.AppSettings["AppSetting3"];
}

然后我的实现将简单地是

OtherClass otherClass = new OtherClass();
var foo = otherClass.SomeMethod();

这让我很烦,但是我不确定为什么。哪种更好的做法,为什么呢?我很抱歉我缺少明显的东西。有时会发生大声笑。 谢谢-弗兰克

3 个答案:

答案 0 :(得分:2)

我不能真正地评论“更好”,因为这是很主观的,但是至少可以说将参数传递给方法而不是让方法去获取它们本身是一种形式依赖注入。依赖注入的优点在于,它减少了类必须知道如何去做/减少任何给定类完成其工作所需的其他类的数量。通常,在OO设计中,我们寻求减少类对其他类的依赖的方法。您可能还会看到通常称为低耦合的概念。与其他类没有高度耦合的类更容易在多个程序中作为独立模块重用

在您的示例中,OtherClass(和/或BaseClass)需要知道ConfigurationManager是什么,这意味着它需要引用其名称空间,并且需要在目标等上具有system.configuration.dll以便可以去获取一些基本的东西(字符串),其中包含完成其工作所必需的信息。如果将字符串提供给该方法,则它可以在不知道ConfigurationManager是什么的情况下完成其工作-您可以在甚至没有任何ConfigurationManager的应用程序中使用它,可能是因为它是从数据库中获取其配置,或者它是单元测试的一部分,可以直接从硬编码中获取一些人为的数据,以确保始终获得给定的结果

当您对类需要做的数据来自上面的概念感到沮丧时,它开始变得更加有意义,为什么像这样传递数据的系统可以与控制反转容器一起使用;本质上是一种软件,它根据有关从何处获取应该传递的数据的一些预配置规则为您创建对象的实例。IoC容器可以查看对象并基于一致的条件决定要传递给哪些参数(例如,其构造函数)规则集,并通过进一步减少对“新”一词的使用,朝着消除依赖关系迈出了一步。可以将其视为编写一个配置文件来描述您的哪些对象需要其他类的哪些实例来完成工作。您可以对IoC容器进行设置,以使其成为一个IniFileConfigSettingsProvider实例,然后将该实例提供给需要某种IConfigSettingsProvider来完成其工作的任何对象。稍后,您将表单ini文件切换为Xml文件。您创建一个名为XmlFileConfigSettingProvider的类,并在IoC中进行注册,它将成为新实例,该实例将传递给需要IConfigSettingsProvider的任何类。至关重要的是,您创建了另一个类,并在IoC中进行了注册,然后在整个程序中使用了它,但您从未自己创建它的实例

如果您曾经听过这样的短语“新的东西就是胶水”,那么通常就是它的含义-当您的OtherClass说var x = new ConfigurationManager... x.Settings["a"]....时,new一词的使用突然使它难以满足需要ConfigurationManager;不知道它是什么就无法运行。这些天的努力通常是让一个类接受“符合某些接口的设置的传入提供程序”或“作为设置的传入基元”-特定于实现但遵循通用接口或无处不在的事物语言中,不需要分别导入。也许您提到的任何一种方法都会困扰您,因为从内心深处您感觉它们都不需依赖于ConfigManager。无论他们是否都需要设置,他们都可以从应该决定使用什么设置的上级链中将其传递给他们。

答案 1 :(得分:2)

在我看来,这取决于您的课程目标。

如果类属于domain classes,则无需依赖于ConfigurationManager类。您可以创建一个构造函数并提供必要的数据:

public class FooClass()
{
    public Property1 {get; private set;}

    public FooClass(string property1)
    { 
        Property1 = property1;
    }
}

如果FooClass属于Service Layer,那么在我看来,它有资格依赖于ConfigurationManager类。

答案 2 :(得分:0)

每种设计和编码选择都会有proscons。正如他们所说,相同的模式可能并不适合所有人。因此,必须根据需要进行自定义。

主要,决策应基于应用程序的用例。让我提供一些场景来描述它。假设在AppSettings中配置的项目在您的应用程序的生存期内不会改变,那么您可以采用一种方法,其中与AppSettings的依赖关系最少。特别是一种var foo = otherClass.SomeMethod(_property1, _property2, _property3);的方法。这与OOD原则相匹配,因为课程将重点放在业务逻辑上。

但是,如果您在一生中看到添加/修改/删除项(即使在极少数情况下),那么上述方法将难以维护。例如,如果根据特定条件需要重新加载AppSettings,则无需重新启动应用程序/ WebServer。有人可能会争辩说为什么将这样的设置保留在AppSettings中,这也是非常有效的。如果您的应用程序需要这种情况,那么最好使用ConfigurationManager.AppSettings而不用担心依赖关系。可以选择扩展它的包装类(Singleton pattern)来管理和提供对ConfigurationManager.AppSettings的访问。