泛型释放并在 c# 中设置为 null
本文关键字:设置 null 释放 泛型 | 更新日期: 2023-09-27 18:32:56
我发现自己为类中的数据库对象执行此操作:
if (Db != null)
{
Db.Dispose();
Db = null;
}
几个问题...
- 我是否应该将 Db 对象设计为寿命更短,因此能够把它放在一个
using
块里吗? - 有没有一种通用的方法可以做到这一点,而不是写 3 行 每次我处理东西时?
撇开这些事情不谈,我对类似的事情是否可能感兴趣:
static void SafeDispose(ref IDisposable obj)
{
if (obj != null)
{
obj.Dispose();
obj = null;
}
}
- 大概是这样。如果不看到更多的班级,就不可能肯定地说。但根据经验,我尽量避免使用一次性字段或属性(我认为就是这样,因为如果它是一个局部变量,你可以使用
using
)。管理它们太难了,除非您的类也IDisposable
并且您在Dispose()
方法中清理它。 - 您可以将这些行重构为它们自己的方法,例如
DisposeDb()
.
public static void MyDispose(ref DbContext db)
{
if (db != null)
{
db.Dispose();
db = null;
}
}
或者类似的东西卡在某个地方的课堂上。
- 有没有一种通用的方法可以做到这一点,而不是每次我处理东西时都写 3 行?
若要以可重用的方式实现类似功能,可以创建静态帮助程序方法:
public static class Disposable
{
public static void Dispose(ref IDisposable obj)
{
if (obj!= null)
{
obj.Dispose();
obj = null;
}
}
}
您可以像这样调用该方法:
Disposable.Dispose(ref someDisposableObject);
这不适用于属性,因为不能将属性传递给ref
参数。要使其也适用于属性,您可以使用表达式:
public static class Disposable
{
public static void Dispose(Expression<Func<IDisposable>> expression)
{
var obj = expression.Compile().Invoke();
if (obj == null)
return;
obj.Dispose();
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null || !IsMemberWritable(memberExpression.Member))
return;
var nullExpression = Expression.Constant(null, memberExpression.Type);
var assignExpression = Expression.Assign(memberExpression, nullExpression);
var lambdaExpression = Expression.Lambda<Action>(assignExpression);
var action = lambdaExpression.Compile();
action.Invoke();
}
private static bool IsMemberWritable(MemberInfo memberInfo)
{
var fieldInfo = memberInfo as FieldInfo;
if (fieldInfo != null)
return !fieldInfo.IsInitOnly && !fieldInfo.IsLiteral;
var propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
return propertyInfo.CanWrite;
return true;
}
}
此方法适用于变量、字段和属性。它释放任何一次性对象,但仅在可写时才将其设置为 null。
您可以以相同的方式释放任何内容,如以下示例中Foo.CleanUp
的方法所示:
public class Bar : IDisposable
{
// ...
}
public class Foo
{
private Bar _barField = new Bar();
public Bar BarProperty { get; set; } = new Bar();
public void CleanUp()
{
Disposable.Dispose(() => _barField);
Disposable.Dispose(() => BarProperty);
var barVariable = new Bar();
Disposable.Dispose(() => barVariable);
}
}