我正在尝试编写代码分析器,以检查是否有未关闭的IDataReader。
我已经阅读了this question,但没有解释如何完成,我还尝试通读了github链接中的文档。此处使用的英语太复杂,我不明白我该怎么做。将能够找到所有类型为IDataReader的实例,并在该类型的任何变量超出范围之前验证在其上调用close()方法。
[我试图在Visual Studio中创建一个具有代码修复功能的Analyzer类型的项目,我试图在我的类的Initialize方法中注册操作上下文(从DiagnosticAnalyzer
类型扩展如下:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class DataReaderAnalyzerAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "DataReaderAnalyzer";
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
private const string Category = "DBConnectionCheck";
private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.RegisterOperationAction((operationContext) =>
{
((Microsoft.CodeAnalysis.CSharp.Syntax.AssignmentExpressionSyntax)((Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax)operationContext.Operation.Syntax).Expression).Left
}
, OperationKind.ExpressionStatement);
}
}
我想找到所有持有类型IDataReader的变量的引用,确保在超出范围之前,在此变量中调用close方法。
我想分析的代码示例如下。
class Program
{
static void Main(string[] args)
{
IDataReader reader = null;
try
{
Database db = DatabaseFactory.CreateDatabase("ApplicationConnection");
reader = GetDataReader(db);
while (reader.Read())
{
//Do somethig with the data here
}
reader.Close();
}
catch (Exception)
{
throw;
}
finally
{
if (reader != null && !reader.IsClosed)
{
reader.Close();
}
}
}
public static IDataReader GetDataReader(Database db)
{
DbCommand dbcmd = db.GetSqlStringCommand("some select statement to get data from oracle data base");
var reader = db.ExecuteReader(dbcmd);
return reader;
}
}
有一个非常简单的方法,它主要涉及忘记Close
,并利用它是IDisposable
的事实-这是这种情况的预期API。然后,它变得非常简单得多-如此简单,以至于a:您不需要专用的分析器,b:与IDisposable
兼容的现有分析器可能为您完成了工作。
using var reader = GetDataReader(db);
while (reader.Read())
{
//Do somethig with the data here
}
带有否try
/catch
/ finally
等;编译器将简单地通过using
添加执行此操作所需的一切。请注意,对于较早的编译器,这需要是:
using (var reader = GetDataReader(db))
{
while (reader.Read())
{
//Do somethig with the data here
}
}
作为旁注:我强烈建议not与ADO.NET API对抗-这不是一种花费时间的有用方法;它是一种有效的方法。像Dapper这样的工具可以执行[[对您来说最常见的事情] >>,因此您无需编写此代码-并且它知道所有需要避免的极端情况。典型的Dapper用法可能是:
string region = ...
var users = connection.Query<User>(
"some * from Users where Region = @region",
new { region } // parameters
).AsList();
该库在内部处理所有ADO.NET详细信息。