2014-09-30 160 views
0

为什么我不能设置一个对象为null鉴于以下扩展方法:在扩展方法

public void DisposeIfNotNull(this IDisposable disposableObject) 
{ 
    if (disposableObject != null) { 
     disposableObject.Dispose(); 
     disposableObject = null; 
    } 
} 

谁能解释为什么下面这行没有任何影响:disposableObject = null;

+0

你与变量的本地副本的工作,你需要用'传递ref',这是你在扩展方法中无法做到的。使'DisposeIfNotNull'返回你的'disposableObject'并将值赋给调用者。 – DGibbs 2014-09-30 11:45:00

+2

你究竟在做什么?您意识到将对象设置为null对GC什么时候收集它没有影响?因此,即使你的方法工作,它也是一个稍微不太有用的'Dispose()'版本,你不能放入'using'块。 – 2014-09-30 11:53:45

+1

我认为这可能是好事,你不能做你想做的事情! – 2014-09-30 11:53:56

回答

6

因为你设置本地参考为null只有 - 你传递的不是参考

如果不是,你可以使用关键字ref的延伸,但是这不是与兼容扩展参数。

0

为了实现可重复使用的方式类似的东西,你可以创建一个静态辅助方法:

public static class Disposable 
{ 
    public static void DisposeIfNotNull(ref IDisposable disposableObject) 
    { 
     if (disposableObject != null) 
     { 
      disposableObject.Dispose(); 
      disposableObject = null; 
     } 
    } 
} 

您可以调用的方法是这样的:

Disposable.DisposeIfNotNull(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); 
    } 
}