为什么我不能在扩展方法中将对象设置为null

时间:2014-09-30 11:36:03

标签: c# extension-methods

给出以下扩展方法:

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

任何人都可以解释为什么以下行没有任何效果:disposableObject = null;

2 个答案:

答案 0 :(得分:6)

因为您只将本地引用设置为null - 而不是您传入的引用。

如果它不是扩展名,您可以使用ref关键字,但这与扩展参数不兼容。

答案 1 :(得分:0)

要以可重用的方式实现类似的功能,您可以创建一个静态辅助方法:

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

你可以这样调用这个方法:

Disposable.DisposeIfNotNull(ref someDisposableObject);

这不适用于属性,因为您无法将属性传递给ref参数。 为了使它也适用于Properties,您可以使用表达式:

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);
    }
}