【发布时间】:2021-08-20 13:47:55
【问题描述】:
这是一个 Windows 窗体应用程序。下面的代码是一个测试数据库连接性的静态类。在页面加载方法中调用Test1.test。
public static class Test1
{
static string cStr = "Data Source=svrname;Initial Catalog=dbname;Integrated Security=true";
public static bool test{ get; } = chkDb();
private static bool chkDb()
{
try
{
using (SqlConnection connection = new SqlConnection(cStr ))
{
SqlCommand command = new SqlCommand("SELECT 1;", connection);
connection.Open();
return true;
}
}
catch {
return false;
}
}
此代码通常适用于文件。但是,如果我输入了一个无效的 dbname,那么它会给出以下未处理的异常,这似乎绕过了 catch 块。当无效的 Windows 用户尝试打开应用程序时,也会发生类似的情况。
System.TypeInitializationException: '类型初始化器 'Project1.Test1' 引发了异常。'
内部异常: SqlException:无法打开登录请求的数据库“dbname”。 登录失败。用户“DOMAINXYZ\User1”登录失败。
我该如何处理这个异常?我尝试过捕获异常、SqlException,但似乎都没有。
【问题讨论】:
-
将其作为静态属性(或根本没有)似乎是个坏主意。数据库的状态可以随时更改,并且不受您的代码的控制。它回答
true并没有告诉您数据库仍然在您尝试使用它时仍然可用。它回答false告诉你它在 5 毫秒前不可用,但没有关于它现在是否可用。 -
非平凡的静态初始化器是邪恶的,像瘟疫一样避免它们。这是您想要这样做的一个例子。这里没有充分的理由使用静态初始化程序;只需使用常规方法使其成为常规实例并在启动代码中调用它。这不能回答为什么这段代码会失败的问题(我认为它实际上不应该,所以这 可能 是 JIT 中的一个错误,或者它可能是静态初始化的一些微妙细节,其中这实际上是预期的结果),但最好避免一开始就问这些问题。
-
更喜欢实例而不是静态;如果您可以集中访问(例如,它仅以一种形式或一个数据访问层类使用)使其成为那里的实例字段并在(非静态!)构造函数中初始化事物,这是一个仅调用一次的单独方法,或者使用
Lazy。您可以将实例传递给那些需要它们的方法,并且只能传递给那些(依赖注入)。如果您必须将其设为静态,请坚持使用Lazy;这使得检索发生的时间可以预测,并且可以在调用代码中捕获异常。 -
我无法重现 TypeInitializationException。您使用的是哪个框架版本?或者你是否过度简化了你的类,使其不再重现错误?
-
@DavidBrowne-Microsoft 如果我错了,请纠正我,但恕我直言,自动属性将有一个
private static readonly <somebackingfield> = chkDb();。所以这可能会在 chkDb 中不使用 try/catch 就抛出 TypeInitializationException。
标签: c# sql-server