【问题标题】:Generic dispose and set to null in c#在 C# 中通用处理并设置为 null
【发布时间】:2013-09-25 16:22:30
【问题描述】:

我发现自己在为班级中的一个数据库对象这样做:

if (Db != null)
{
    Db.Dispose();
    Db = null;
}

几个问题……

  1. 我是否应该将 Db 对象设计为具有更短的寿命,等等 能把它放在using 块中吗?
  2. 有没有一种通用的方法可以做到这一点,而不是写 3 行 每次我处理东西?

抛开这些不说,我感兴趣的是是否有可能发生类似的事情:

static void SafeDispose(ref IDisposable obj)
{
    if (obj != null)
    {
        obj.Dispose();
        obj = null;
    }
}

【问题讨论】:

  • 就像你提到的,如果对象实现了 IDisposible,你可以使用 using.对于数据库的东西,我建议你使用 using 语句。
  • 是什么导致您避免使用 using 块?
  • 这段代码是否在包含类的Dispose() 方法中?如果是这样,这个 SO 问题是在问同样的事情:Disposing the members that implement IDisposable。它有一个非常好的解决方案。此外,如果这是在 Dispose() 方法中,则无需设置 Db = null; 它没有任何好处。

标签: c# .net


【解决方案1】:
  1. 可能是这样。如果没有看到更多的课程,就不可能肯定地说。但根据经验,我尽量避免使用一次性的字段或属性(我假设是这样,因为如果它是一个局部变量,你可以使用using)。管理它们太难了,除非你的类也是 IDisposable 并且你在 Dispose() 方法中清理它。
  2. 您可以将这些行重构为它们自己的方法,例如DisposeDb()

【讨论】:

    【解决方案2】:
        public static void MyDispose(ref DbContext db)
        {
            if (db != null)
            {
                db.Dispose();
                db = null;
            }
        }
    

    或类似的东西卡在某个班级的某个地方。

    【讨论】:

      【解决方案3】:
      1. 是否有一种通用的方法来执行此操作,而不是每次处理某些东西时都写 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);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-07-28
        • 1970-01-01
        • 1970-01-01
        • 2012-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-25
        • 2012-12-31
        相关资源
        最近更新 更多