Правильно избегайте ObjectDisposedException

Я столкнулся с проблемой, когда ObjectDisposedException выбрасывается примерно в 50% случаев. Код внутри try (внутри finally) ниже вызывает исключение. Я не знаю, как с этим справиться. Я мог бы просто съесть исключение, как показано ниже, но есть ли способ проверить и закрыть объект без возникновения исключения?

    public static FindResponse Discover(FindCriteria findCriteria, 
                                        DiscoveryEndpoint discoveryEndpoint = null)
    {
        DiscoveryClient discoveryClient = null;

        try
        {
            if (discoveryEndpoint == null) { 
                 discoveryEndpoint = new UdpDiscoveryEndpoint(); 
            }

            discoveryClient = new DiscoveryClient(discoveryEndpoint);

            return discoveryClient.Find(findCriteria);
        }
        finally
        {
            try
            {
                if (discoveryClient != null)
                {
                    discoveryClient.Close();
                }
            }
            catch (ObjectDisposedException)
            {
                // Eat it.
            }
        }
    }

person Bob Horn    schedule 05.02.2015    source источник
comment
Не могли бы вы опубликовать трассировку стека?   -  person Rohit Prakash    schedule 05.02.2015


Ответы (3)


Как насчет

public static FindResponse Discover(FindCriteria findCriteria, DiscoveryEndpoint discoveryEndpoint = null)
{
    if (discoveryEndpoint == null) 
      discoveryEndpoint = new UdpDiscoveryEndpoint();

    using (var client = new DiscoveryClient(discoveryEndpoint))
    {
        return client.Find(findCriteria);
    }
}

Обновить

Кажется, DiscoveryClient.Dispose() будет генерировать исключения. Оригинальный подход OP кажется единственным приемлемым ответом.

person Richard Schneider    schedule 05.02.2015
comment
Я должен был подумать об этом. :) Спасибо. - person Bob Horn; 05.02.2015
comment
Ааааа!! Я снова получаю исключение! Возможно, мне просто придется поймать его и съесть. - person Bob Horn; 05.02.2015
comment
О, я видел эту же проблему (Close and Dispose) с клиентами WCF. Лучше просто съесть его, как вы первоначально предложили. См. stackoverflow.com/questions/23867/< /а> - person Richard Schneider; 05.02.2015

Хотя я не совсем уверен, почему вы сталкиваетесь с этим, но вы можете попробовать следующее для обычного клиента WCF:

Если у вас есть свойство «State», доступное для discoveryClient, попробуйте выполнить следующие защитные проверки:

finally
        {
            try
            {
                if (discoveryClient != null) 
                { 
                  if(discoveryClient.State == CommunicationState.Faulted)
                  {
                     discoveryClient.Abort();
                  }
                  else if(discoveryClient.State != CommunicationState.Closed )
                  {
                     discoveryClient.Close();
                  }
            }
            catch (ObjectDisposedException)
            {

            }
        }

Надеюсь, это поможет вам.

person Siva Gopal    schedule 05.02.2015
comment
Не может ли состояние измениться между вашим if чеком и тем, что находится внутри if? - person Bob Horn; 05.02.2015
comment
@BobHorn Ты прав. Но из MSDN состояние закрытия является временным и вместо этого было бы лучше проверить непереходное состояние Closed и соответствующим образом обновить мой ответ. Также состояние Faulted — это еще одно состояние, в котором мы должны закрыть канал только с помощью Abort. + Как вы упомянули изначально, если все эти состояния почему-то выскальзывают, то лучше проглотить :) - person Siva Gopal; 05.02.2015
comment
Спасибо. В вашем примере нам все равно нужно поймать и съесть исключение, но, по крайней мере, код четко указывает, что он делает. +1 за подсказку, но я просто собираюсь поймать и съесть исключение, не беспокоясь о других состояниях. Иногда просто устаешь писать такой код. :) - person Bob Horn; 05.02.2015
comment
@BobHorn Но если вы пойдете по пути определения пользовательской оболочки вокруг своего канала связи, а затем вы сможете инкапсулировать в нее эту обработку состояния, чтобы вы меньше всего беспокоились о распространении этих проверок состояния по кодовой базе. - person Siva Gopal; 05.02.2015

Также я бы рекомендовал использовать «using» для объектов IDisposable. Учитывая, что DiscoveryClient является IDisposable,

public static FindResponse Discover(FindCriteria findCriteria, DiscoveryEndpoint discoveryEndpoint = null)
    {

        FindResponse response = null;
        try
        {
            if (discoveryEndpoint == null) { discoveryEndpoint = new UdpDiscoveryEndpoint(); }

            using (DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint))
            {
                response = discoveryClient.Find(findCriteria);
                discoveryClient.Close();
            }
        }
        finally
        {   
            // other finalizing works, like clearing lists, dictionaries etc.
        }
        return response;
    }
person Rohit Prakash    schedule 05.02.2015
comment
Извините, но finally {} не работает. - person Richard Schneider; 05.02.2015
comment
@RichardSchneider, я думаю, я правильно отредактировал код. . .. . - person Rohit Prakash; 05.02.2015