2016-11-28 8 views
5

Podczas implementacji wzoru Dispose, właściwości obiektu powinny generować ObjectDisposedException po usunięciu obiektu.Korzystanie z ObjectDisposedException

Wydaje się, że wiele powtarzających się kodów, jeśli każda właściwość i metoda ma linię kodu na początku settera, a program pobierający wyrzuci ten wyjątek, nawet jeśli jest to tylko ThrowIfDisposed(). Jeśli masz 40 właściwości, to jest 80 powtarzających się linii. W dużej klasie może się bardzo szybko sumować.

Nie byłem w stanie znaleźć lepszego sposobu, więc wygląda na to, że tak właśnie jest, ale myślałem, że zapytam. Czy istnieje lepszy sposób?

+0

Jednorazowy wzór był błędem .NET 1.x, którego bardzo trudno się pozbyć. Naprawiono dokładnie w .NET 2.0 z krytycznymi finalizatorami zaimplementowanymi w klasach SafeHandle. Jedynym pozostałym zastosowaniem tego wzorca jest to, kiedy klasa podstawowa go implementuje, zmuszając również do radzenia sobie z nim. Przesyłanie kodu za pomocą rzutów nie poprawia go, wystarczy polegać na klasie bazowej, aby rzucić wyjątek. –

+0

Dziękuję za uwagi. Będę musiał zajrzeć do klasy SafeHandle. Nigdy nie podobał mi się wzór jednorazowego użytku i chciałbym znaleźć lepszy zamiennik. – JHJ

Odpowiedz

7

Jeśli masz 40 właściwości w jednej klasie, prawdopodobnie masz problem z projektowaniem, ale dzieje się dalej ... To naprawdę zależy od konkretnego przypadku użycia, ale powinieneś rzucić tylko ObjectDisposedException, jeśli właściwość nie może faktycznie zostanie rozwiązany, ponieważ klasa została usunięta. Dać konkretny przykład:

public class MyStream : IDisposable 
{ 
    private string name; 
    private Stream stream; 

    public MyStream(string name) 
    { 
     this.Name = name; 
     this.Stream = new FileStream(...); 
    } 

    public string Name 
    { 
     get 
     { 
      return this.name; 
     } 
    } 

    public Stream Stream 
    { 
     get 
     { 
      if (this.IsDisposed) 
      { 
       throw new ObjectDisposedException(); 
      } 

      return this.stream; 
     } 
    } 

    private bool IsDisposed { get; set; } 

    public void Dispose() 
    { 
     if (!this.IsDisposed) 
     { 
      this.IsDisposed = true; 
      this.Stream.Dispose(); 
      this.Stream = null; 
     } 
    } 
} 

tutaj właściwość Stream zgłasza wyjątek, ponieważ podstawowa strumienia zostały usunięte, tak, że nie można ich stosować. Ale Name nie ma powodu do rzucania. Stamtąd, w wielu przypadkach można na czynniki swój kod tak, że dostęp do rzeczywistej własności problematycznej rzuca wyjątek:

public int Length 
{ 
    get 
    { 
     // Since we access the Stream property, the ObjectDisposedException 
     // will be thrown when the class is disposed 
     return this.Stream.Length; 
    } 
} 

Jeśli nadal masz zbyt wiele właściwości do dekoracji nawet po zastosowaniu tego wzoru, możesz używać bibliotek takich jak Fody, które pozwalają wstrzykiwać zachowanie w czasie kompilacji. Używając go, możesz utworzyć atrybut, który chcesz zastosować w zależności od potrzeb.

+1

Zgadzam się, że ponad 40 obiektów jest dużo i zwykle oznacza to, że zbyt wiele zostało spakowanych w jedną klasę, która powinna zostać rozbita, ale czasami jest to jedyny sposób. Excel jest przykładem. Praca z nim skłoniła mnie do zadawania tego pytania. Na przykład klasa Range ma 99 właściwości i 87 metod. Praca z COM z .NET to ból w **. Po usunięciu obiektu i usunięciu wszystkich zasobów programu excel wszelkie właściwości lub metody korzystające z programu Excel zwrócą wyjątki wskaźnika pustego. Wydaje się to nieeleganckie, ale może właśnie w tym przypadku rozwiązaniem jest dopuszczenie wyjątków zerowych. – JHJ

0

Sprawdź inny wątek: Handling ObjectDisposedException correctly in an IDisposable class hierarchy

Nie trzeba rzucać wyjątek każdym razem, gdy ktoś własności dostępu klasy implementującej :IDisposable. Jest to konieczne tylko wtedy, gdy uzyskujesz dostęp do obiektu, który musi zostać usunięty (np. Zapis/odczyt do plików, dostęp do gniazd sieciowych ...). We wszystkich innych przypadkach możesz po prostu przejść z pomysłem do normalnej klasy.

Zwykle obiekty/klasy nie mają tak dużej liczby właściwości, ponieważ istnieje opcja podziału ich na kilka klas -> które pozwolą Ci wykonać tylko część tego :IDisposable, a reszta będzie niezależna od IDisposable klasa.