2014-09-30 138 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); 
    } 
}