2012-01-05 16 views
13

Mam klasę statyczną ze statycznym konstruktorem, która zajmuje trochę czasu (10-15 sekund), aby wykonać i w pełni zainicjować klasę. Aby poprawić wydajność, postanowiłem włączyć jawnie inicjalizację tej klasy statycznej zamiast wtedy, gdy jest ona po raz pierwszy potrzebna, tak aby była gotowa do użycia, gdy faktycznie musi być użyta.Jak zainicjować klasę statyczną C#, zanim będzie faktycznie potrzebna?

Moja pierwsza myśl polegała na stworzeniu metody Initialize() dla tej klasy, ale ponieważ mam już konstruktor statyczny, ta metoda nie wymaga niczego innego, jak tylko wywoływania metody jawnej inicjalizacji klasy bez dostęp do innych jego publicznych metod lub właściwości. Posiadanie metody, która nie robi nic bezpośrednio, nie wydaje mi się właściwe.

Potem pomyślałem, że mogę po prostu przenieść kod z konstruktora statycznego do tej metody Initialize(), ale chciałbym również, aby klasa została zainicjowana, kiedy jest potrzebna, a metoda Initialize() nie została jawnie wywołana.

Podsumowując, chcę następujące kryteria, których należy przestrzegać:

  • Chcę umożliwić klasa statyczna być jawnie zainicjowana (prawdopodobnie za pomocą publiczną metodę Initialize()).
  • Nie chcę mieć dostępu do żadnych innych publicznych metod lub właściwości w klasie, gdy ich nie potrzebuję, nawet jeśli zainicjowałoby to klasę statyczną.
  • Jeśli klasa nie została jawnie zainicjowana, nadal chcę ją zainicjować, kiedy jest ona potrzebna (tj. Podczas uzyskiwania dostępu do innych publicznych metod lub właściwości z zamiarem wykorzystania dostarczanej funkcji lub danych).
  • To jest klasa pomocnicza, a użycie wzorca projektowego Singleton nie jest konieczne do moich celów.

Jaki byłby właściwy sposób przestrzegania powyższych kryteriów dla klasy statycznej napisanej w języku C#? Może to również dotyczyć innych języków programowania (np. Java), ale osobiście interesuje mnie rozwiązanie napisane w języku C#.

+0

Dlaczego nie zainicjować klasę w statycznym konstruktorze? Uważam, że twoje pragnienie, aby ręcznie zainicjować niepotrzebne. – ChaosPandion

+0

http://msdn.microsoft.com/en-us/library/bb397680.aspx – Venki

+0

Czy "statyczna" klasa "inicjująca" nie * jest klasą statyczną? Jaki byłby cel takiego zachowania? Wygląda na to, że zamiast tego chcesz utworzyć instancję klasy na podstawie wartości statycznych. –

Odpowiedz

14

to pewnie po prostu pójść na metodzie Initialize - i to może zrobić coś pożytecznego:

  • może zalogować że jesteś wyraźnie próbuje zainicjować klasę z śladu stosu
  • to może rzucić wyjątek, jeśli klasa jest już zainicjowany przez innego Initialize rozmowy
  • mogli Państwo ewentualnie (przy odrobinie wysiłku i reorganizacji) sortuj rzeczy tak, aby wszelkie wyjątki wywoływane podczas inicjowania były propagowane bez tego, co normalnie otrzymałeśby TypeInitializationException.
+0

Jak ustalić, czy klasa statyczna została już zainicjowana? Nie używam wzorca Singleton, więc nie mam instancji klasy do odniesienia. Konstruktor statyczny jest zawsze wywoływany przed ciałem metody 'Initialize()', więc statyczne elementy są zawsze inicjowane. Nie widzę, jak mogę to zrobić bez użycia wzorca Singleton. – Bernard

+1

@Bernard: Zachowałbyś statyczną zmienną, by powiedzieć, czy 'Initialize' został wywołany jako pierwszy. Zauważ, że część wywoławcza "via Another Initialize" ustawi wartość tylko "Initialize", ale konstruktor statyczny * przetestuje *, czy był już ustawiony. –

+0

Dzięki za wyczyszczenie tego! – Bernard

2

Nie jestem pewien, czy można określić, kiedy załadowany jest konstruktor statyczny.

Z MSDN "Statyczny konstruktor jest wywoływany automatycznie w celu inicjalizacji klasy przed utworzeniem pierwszej instancji lub odniesienia do wszystkich elementów statycznych."

http://msdn.microsoft.com/en-us/library/k9x6w0hc(v=vs.80).aspx

* EDIT: * Byłoby dodanie Singleton pomoc tutaj? Program pobierający może wywołać funkcję Initialize(), zaznaczając flagę w klasie IsLoaded = true.Kolejne rozmowy nie zadzwoni Initialize()

+0

Rozumiem, że konstruktor statyczny nie może być wywołany jawnie, ale chcę zezwolić na działanie klasy, aby powiedzieć: "Tak, chcę, aby ta klasa została zainicjowana teraz!" jednocześnie pozwalając, "Nie zainicjowałem cię, ale proszę zainicjuj się, zanim zacznę cię używać." – Bernard

+0

Używanie wzorca Singleton wymusiłoby użycie metody 'Initialize()', ponieważ trzeba jawnie utworzyć pojedynczą instancję klasy. Po prostu uważam, że nie muszę utrzymywać instancji tej klasy, ponieważ używam tej klasy jako klasy pomocniczej i nie muszę przekazywać jej instancji jako argumentu do innych metod klasy. – Bernard

17

Wybrałbym metodę initialize (EDYCJA: Zobacz odpowiedź Jona). Ale jeśli naprawdę prostu chcesz użyć konstruktora, można to zrobić:

var type = typeof (YourType); 
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); 

RunClassConstructor pozwala wymusić konstruktora klasy (konstruktor statyczny), aby uruchomić, jeśli już nie ma. Jeśli już został uruchomiony, powiedzmy, ponieważ użyłeś statycznego elementu klasy, nie ma to żadnego wpływu. Uruchomienie tego dodatkowego czasu nie ma żadnego efektu.

+0

Interesujące podejście. Nie tego chciałbym użyć, ale dobrze jest wiedzieć, że to opcja. – Bernard

0

Podejście nie wydaje mi się obrzydliwe. Mogę nazwać metodę Touch(), nadać jej puste ciało i dodać odpowiedni komentarz. Czy to wystarczy, żebyś przeszedł przez twoje poczucie, że coś nie jest w porządku z tym?

+2

Niezupełnie. Nigdy nie myślałem, że zaprojektuję klasę metodą "Touch()". Czuje się brudno. :) – Bernard

+0

Zastanawiam się, czy wpisanie 'var type = typeof (ClassToInitialize)' byłoby wystarczające, chociaż nie wiem czy zostałoby skompilowane. – Hatchling

2

dwa obejścia:

  1. przenieść kod konstruktora do Initialize() tak można nazwać jednoznacznie. I zastąpić kod wewnątrz konstruktora po prostu wywołać metodę w przypadku Initialize() klasa statyczna jest ładowany dynamicznie zanim pan nazwał go wyraźnie

    public static class StaticClass 
    { 
        // actual constructor 
        static StaticClass() 
        { 
         Initialize(); 
        } 
    
        // explicit "constructor" 
        public static void Initialize() 
        { 
         MyProperty = "Some Value"; 
        } 
    
        public static string MyProperty { get; set; } 
    
    } 
    

    Następnie zainicjować tak, jeśli chcesz:

    StaticClass.Initialize(); 
    

    Lub zostanie zainicjowany dynamicznie po raz pierwszy jest on używany

  2. Nie jako semantycznie nietknięty, ale możesz aktywować inicjalizację organiczną klasy statycznej, po prostu zażywając własność i rzucając ją w tymczasowy zmienna.

    Więc po prostu to zrobić:

    // trigger static initilaization 
    var dummy = StaticClass.MyProperty; 
    

    Wciąż pozwala nazwać to, kiedy trzeba, ale jeśli istnieje jakiś koszt wydajność na inicjalizacji, można spróbować powołać go na starcie, raczej niż pierwszy czas, w którym użytkownik robi coś, co uruchamia ten kod.

Dla innego pomocnego zarysu statycznej inicjalizacji patrz: Is the order of static class initialization in C# deterministic?

Powiązane problemy