首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用静态时识别风险/Gotchas

使用静态时识别风险/Gotchas
EN

Software Engineering用户
提问于 2020-12-20 20:43:44
回答 1查看 145关注 0票数 1

我打算从开发选择、代码评审和针对定义的环境(开发、测试、生产等)的一般测试的角度出发。我将使用C#作为主要的编码参考。

我想要的是:

  • 下面的代码更改是否可能被认为是潜在的风险?(我不知道在代码评审/测试过程中,这是否会被视为一种代码气味或一种可识别的风险)
  • 下面的问题似乎是特定于环境的、可能的IIS/Server配置差异。这个项目可能太宽泛了,所以如果结果是这样的话,我会删除它。是否有方法确定web应用程序是否由于IIS/Server中的特定设置而面临失败/引发异常的风险?

详细信息:

最近,在日志记录相当差的WebForms应用程序中,在代码更改后,我遇到了一个“类型初始化'X‘抛出异常”错误。异常来自的类看起来类似于以下内容:

代码语言:javascript
复制
public class someModelClass
{
    private static string someConnection = new someConnectionStringRequester().GetConnection(someParam1, someParam2, ...); // <- this was the primary change. someConnectionStringRequester is not a static class/doesn't have static methods
    //some public properties

    public static List<someModelClass> getInstancesOfModel(someParam1, someParam2, ...)
    {
        //return some list of models based on someConnection 
    }
}

还有其他几个“模型”类,它们遵循相同的模式,差别很小。

在最初的测试(开发和测试环境)中,应用程序没有遇到任何异常。一旦部署到生产环境中,它就会启动异常。在更改之前,我做了两件事,检查了代码,并添加了一些更好的日志记录。这个类以前是这样的:

代码语言:javascript
复制
public class someModelClass
{
    private static string someConnection = someOtherConnectionStringRequester.GetConnection(someParam1, someParam2, ...); // <- this was the original compared the the primary change above. someOtherConnectionStringRequester was a static class/had static methods
    //some public properties

    public static List<someModelClass> getInstancesOfModel(someParam1, someParam2, ...)
    {
        //return some list of models based on someConnection 
    }
}

在进行日志记录之后,我不得不强制执行一个异常,以确保我能够得到更多的细节。我使用GetConnection方法“抛出新异常(‘testMessage’)”。如前所述,有多个“模型”类看起来像这个类,但是强制异常抛出了一个不同的类抛出类型初始化程序异常,这个类在抛出异常的初始类之前被调用。这个不同的类看起来如下:

代码语言:javascript
复制
public class someDifferentModelClass
{
    private static string someConnection = new someConnectionStringRequester().GetConnection(someParam1, someParam2, ...); // <- this also had a similar change
    //some public properties


    public void someAction()
    {
        someConnectionStringRequester someOtherConnection = new someConnectionStringRequester();
        // do some work based on someOtherConnection 
        getInstancesOfModel(someParam1, someParam2, ...)
        // do some other work
    }

    private static List<someModelClass> getInstancesOfModel(someParam1, someParam2, ...)
    {
        //return some list of models based on someConnection
    }
}

这似乎指向了类第一次调用时、私有静态变量被调用时或两者混合的问题。

如果有任何信息需要澄清或添加才能理解上述内容,请告诉我。

EN

回答 1

Software Engineering用户

回答已采纳

发布于 2020-12-21 20:00:06

使用静态初始化时,您将放弃对初始化顺序的任何显式控制。如果事情成功,原因如下之一:

  • 静态初始化只涉及常量表达式。
  • 您已经仔细阅读了语言规范,并得出结论,初始化工作是正确的。
  • 事情只是偶然发生的。

在您的场景中用来工作的初始化更像是一个意外,尽管它符合语言规范:旧类大概有一个静态构造函数,因此确实保证在调用构造函数之前初始化它的静态字段。现在,您的类没有静态构造函数,因此不能保证按不同的顺序初始化不同的静态变量。有关参考,请参见关于堆栈溢出的问题:C#中静态类初始化的顺序是确定的吗?

一种可能的解决方案是将初始化推迟到运行时,即在第一次访问属性时延迟建立连接。这并不能防止所有潜在的问题(例如,它可能导致循环依赖的无限递归),但它通常确保正确的初始化顺序。这种方法的另一个问题是,在访问属性之前,错误不会变得明显:我们将此代码从初始化时推迟到运行时。

还有一个原因,为什么应该在运行时执行尽可能多的初始化:您的代码(例如,在Main()中)可以在初始化之前执行安装程序。这也极大地帮助了可调试器。

正确地进行初始化是一个非常困难的问题。在C++中出现几个分段错误之后,我学到了避免静态初始化的经验,但是C#也遇到了同样的问题:任何依赖于特定静态初始化顺序的代码都会中断。

有更优雅的方法可用于初始化。

  • 例如,辛格尔顿可能管理连接的生存期(可能使用延迟初始化)。
  • 连接也可能由依赖注入机制提供--可能根本不涉及任何静态变量。
  • 在许多情况下,手动管理所有依赖项是可行的,例如将数据库连接传递给模型类的构造函数。
  • 许多架构认为数据库连接不应该是数据模型的一部分,并将连接外包到存储库对象。但是,这将涉及对您的体系结构进行剧烈的更改,并且可能是不可行的。
票数 2
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/420222

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档