2009-10-08 8 views
7

Jeśli masz pędzla i pióra jak w:Jak obchodzić się z przedmiotami jednorazowymi, do których nie mamy odnośników?

Brush b = new SolidBrush(color); 
Pen p = new Pen(b); 

i wyrzucać je tak:

b.Dispose(); 
p.Dispose(); 

Jak można wyrzucać go, jeśli to było:

Pen p = CreatePenFromColor(color) która stworzyłaby pędzel i długopis dla ciebie? Nie mogę wyrzucić szczotki z tej metody, prawda?

Czy ta metoda nie może być używana z przedmiotami jednorazowymi?

EDYCJA: Chodzi o to, jak pozbyć się SZCZOTKA?

+0

o.O Nie wiedziałem, że Brush and Pen implementuje IDisposable ... –

+0

lol, to na pewno robi. –

+0

Ale gdzie jest ten odnośnik? Dlaczego (i gdzie) tworzysz je, jeśli zwracasz tylko pióro jako wynik metody? – Groo

Odpowiedz

9

Jest to zadanie metody CreatePenFromColor w celu pozbycia się instancji pędzla.Nie jest to oczywiste na pierwszy rzut oka, ale jeśli zagłębisz się w implementację klasy Pióra, zobaczysz, że nie wytrzymuje ona przekazanej instancji Pędzla. Zamiast tego po prostu używa go do obliczenia kilku wartości. Tak więc nie ma powodu, aby instancja Pędzla przeszła poza wywołanie CreatePenFromColor, a metoda powinna pozbywać się instancji.

+0

Dzięki Jared, nie wiedziałem o tym. –

+0

To niekoniecznie musi być prawda. konstruktor Pen przekazuje uchwyt pędzla do 'GdipCreatePen2'. Nie wiem, czy 'GdipCreatePen2' potrzebuje szczotki, aby pozostać przy życiu (funkcja jest ledwo udokumentowana), ale zgaduję, że tak.Pamiętaj, że pędzel może być "TextureBrush" z obrazem, a Ty nie chcesz, aby pióro tworzyło osobną kopię obrazu w pamięci, abyś mógł pozbyć się pędzla. – SLaks

+1

@Slaks, GdipCreatePen2 AFAIK nie wymaga tego, aby pozostać przy życiu. Przeszukałem bardzo ograniczoną dokumentację i wystarczy tylko ustawić pióro, a nie je utrzymywać. – JaredPar

6

Po zakończeniu pracy musisz go wyrzucić.

Na przykład, można nazwać tak:

using (Pen p = CreatePenFromColor(color)) 
{ 
    // do something 
} 

Jeśli metoda zwraca IDisposable obiektu, to jest twój obowiązek, aby go zbyć.

[Edytuj] Teraz mam pytanie - używasz konstruktora Pen (Brush b).

a. W tym przypadku wydaje się, że Pen nie potrzebuje instancji Brush po konstruktorze, więc Twoja metoda może wyglądać następująco:

public Pen CreatePenFromColor(Color c) 
{ 
    using (Brush b = new SolidBrush(c)) 
    { return new Pen(b); } 
} 

b. Dlaczego po prostu nie użyć Pen(Color color)?

public Pen CreatePenFromColor(Color c) 
{ 
    return new Pen(c); 
} 

c. (w odniesieniu do komentarza) Jeśli pióro miałoby wewnętrzną referencję do pędzla, nie byłbyś w stanie go wyrzucić przed skończeniem długopisu. W tym przypadku, chciałbym iść do klasy, która będzie wykonać zadanie dla mnie:

public class PenHelper : IDisposable 
{ 
    private readonly Brush _brush; 
    public PenHelper(Color color) 
    { 
     _brush = new SolidBrush(color); 
    } 

    public Pen CreatePen() 
    { 
     return new Pen(_brush); 
    } 

    public void Dispose() 
    { 
     _brush.Dispose(); 
    } 
} 

a następnie wykorzystać go tak:

using (PenHelper penHelper = new PenHelper(Color.Black)) 
{ 
    using (Pen pen = penHelper.CreatePen()) 
    { 
      // do stuff 
    } 
} 

Zastrzeżenie: IDisposable nie jest realizowany zgodnie z wytycznymi, ale raczej tylko do demonstracji. Cały przykład jest używany tylko do pokazania, jak enkapsulować referencję, gdy jest taka potrzeba. Powinieneś pójść na Pen (kolor) oczywiście.

+0

+1 za "dlaczego ludzie tworzą pędzle do tworzenia długopisów z?!?" –

+0

Dzięki. W twoim przykładzie a, pędzel b zostanie usunięty, gdy tylko Pen zostanie zwrócony, prawda? Jeśli Pen miałby odniesienie do pędzla b, to rzuciłoby to przykład? Zastanawiam się. –

+0

Dzięki za przedłużony przykład. –

0

Gdy metoda pozbawia wystąpienie IDisposable, jednocześnie przekazuje odpowiedzialność za całe życie.

Teraz obowiązkiem osoby wywołującej jest pozbycie się przedmiotu po użyciu. Jeśli ten obiekt zawiera inne obiekty IDisposable, zgodnie z konwencją musimy się spodziewać, że pojemnik będzie prawidłowo pozbywał się jego dzieci, kiedy go wyrzucimy - w przeciwnym razie oznaczałoby to błąd w pojemniku.

W tym konkretnym przypadku należy się spodziewać, że pióra będą pozbywać się wewnętrznej instancji pędzla po jej utylizacji.

+0

Kolory są również jednorazowe? –

+1

Nie, kolor jest strukturą. – Groo

+1

@Joan Venge: "Typo" - poprawiłem go jednocześnie z Twoim komentarzem ... –

2

Twój problem nie ma ogólnego rozwiązania.

W twoim konkretnym przykładzie nie stanowi to problemu, ponieważ Pen ma konstruktor, który bezpośrednio pobiera kolor.

Niektóre klasy będą udostępniały same parametry konstruktora (szczególnie klasy związane ze strumieniem); sprawdź każdą klasę w Reflectorze.

Jeśli klasa, do której powracasz, dziedziczy po Komponencie, możesz dodać moduł obsługi do zdarzenia Zbanowany.

Jeśli zwracana klasa nie jest zapieczętowana, można utworzyć dziedziczoną wersję, która również usunie obiekt, z którego została utworzona.

Wreszcie, jeśli naprawdę chcesz, możesz utworzyć klasę opakowania, która zawiera zwracany obiekt i udostępnia parametr konstruktora. Byłoby to jednak bardzo mylące i nie polecałbym tego.

+0

Dzięki, nie wiedziałem, że Pen może bezpośrednio pobrać kolor. To zabawne, ponieważ widzę mnóstwo kodu tworzącego pędzel i długopis osobno, a następnie za pomocą pióra do malowania. –

+0

Następnie powinieneś przyjąć tę odpowiedź. – SLaks

+0

Tak, robi. Nie ma po prostu czystego, ogólnego rozwiązania tego problemu. – SLaks

1

Jednym z moich warkoczyków z wieloma klasami związanymi z grafiką jest to, że nie ma spójnego wzorca do radzenia sobie z takimi problemami. W rzeczywistości potrzebny jest sposób na częściowe liczenie referencji. Nie w stylu COM, gdzie przekazywanie referencji wymaga ciągłego podwajania liczników referencji, ale w sposób, w jaki, biorąc pod uwagę IDisposable obiekt graficzny, można zażądać innej instancji, która dzieli ten sam podstawowy zasób. Same zasoby byłyby enkapsulowane we wspólnym obiekcie z licznikiem referencyjnym. Utworzenie kolejnej instancji odwołującej się spowoduje zwiększenie licznika; calling Unieruchomienie na instancji odwołującej zmniejszy ją. Pozwoli to uniknąć 95% ogólnego narzutu zliczania referencyjnego, przy jednoczesnym zachowaniu 99% korzyści.