Параметр интерфейса метода как эталонные проблемы

Если у кого-то есть лучшее название, дайте мне знать.

Я сделал DisposeHelper вместо этого:

private Something _thing;

void Dispose()
{
    if(_thing != null)
    {
        _thing.Dispose();
        _thing = null;
    }
}

... я мог бы сделать это:

private Something _thing;

void Dispose()
{
    DiposeHelper.Dipose(ref _thing);
}

Но, по-видимому, я не могу передать DisposeHelper.Dispose IDisposable в качестве ссылки, если только я не использую Something как IDisposable, например:

private Something _thing;

void Dispose()
{
    IDisposable d = _thing;
    DiposeHelper.Dipose(ref d);
}

... что означало бы, что оно не аннулирует исходное поле.

Вот более абстрактный пример. DoThis работает, DoThis нет:

public class Test
{
    public Test()
    {
        Something o = new Something();

        DoThis(o);

        DoThat(ref o);
    }

    private void DoThis(IFoo obj) { }

    private void DoThat(ref IFoo obj) { }
}

public class Something : IFoo { }

public interface IFoo { }

Почему я не могу это сделать?


person George R    schedule 29.01.2011    source источник


Ответы (3)


Я не знаю технической причины, почему вы не можете.

Однако это работает:

var o = new Something();
DoThat(ref o);

private void DoThat<T>(ref T obj) where T : class, IFoo { 
    obj = null;
}
person Rob    schedule 29.01.2011

Это не работает, потому что типы параметров для выражений ref и out должны точно совпадать. Представьте, если бы у DoThat была такая реализация:

private void DoThat(ref IFoo obj)
{
    obj = new SomeOtherImplementationOfFoo();
}

Теперь этот код:

Something o = new Something();
DoThat(ref o);

в итоге o ссылается на экземпляр SomeOtherImplementationOfFoo вместо Something, что явно не может быть правильным.

Вот почему ref работает именно так, а ответ Роба дает способ обойти это.

person Jon Skeet    schedule 29.01.2011

Это не работает, потому что тип должен быть точным типом свойства.

Представьте, что вы можете передать Derived как Base в функцию по ссылке. Теперь функция присваивает параметру новый объект, который является Base, но не Derived. бум

private Derived d;

void Modify(ref Base b)
{
  b=new Base();
}

Modify(ref d);//Booom

Обходной путь использует общий параметр, как в ответе Роба.

public static void DisposeAndNull<T>(ref T x)
  where T:IDisposable
{
  x.Dispose();
  x=null;
}
person CodesInChaos    schedule 29.01.2011