Kiedy używać statycznych konstruktorów?

0

Natknąłem się na przypadek użycia statycznych konstruktorów
Teoretyczny opis:
https://docs.microsoft.com/pl-pl/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

Konstruktor statyczny służy do inicjowania dowolnych danych statycznych lub do wykonywania określonej akcji, która musi zostać wykonana tylko raz. Jest on wywoływany automatycznie przed utworzeniem pierwszego wystąpienia lub odwołaniem do jakichkolwiek statycznych elementów członkowskich.

Kiedy należy używać takich konstrukcji? Czy możecie podać przykłady?

4

Jak tworzysz statyczne dane :D
Zdaje się że w Javie odpowiednikiem tego jest statyczny blok inicjalizacyjny

4

w teorii, żeby np. wczytac plik konfiguracyjny i na jego podstawie ustawić zmienne w statyczne.
w praktyce to po prostu bardzo zły pomysł. W zasadzie nie spotykam użycia w kodzie od dawna (kiedyś bywało).

1

To w C++ miało więcej sensu, dzieje się to tam w momencie ładowania całej binarki, czyli naprawdę wcześnie, i DOKŁADNIE wiadomo kiedy

W VM ładujących per/class utraciło zdecydowanie znaczenie, na wiele sposobów obiektowo to się da załatwić

2
Marcin Marcin napisał(a):

Kiedy należy używać takich konstrukcji? Czy możecie podać przykłady?

Należy nie należy - można użyć inicjalizatora pola, ale jeśli jakaś logika miałaby być wielolinijkowa, to można przenieść do konstruktora.

Praktyczny przykład może być np. taki, że masz sobie klasę Generyczna<T> i chcesz sobie przechować gdzieś jakieś runtime info na temat typu T.

class Generyczna<T>
{
    private static IEnumerable<string> metody;

    static Generyczna()
    {
        metody = typeof(T).GetMethods().Select(p => p.Name);
    }

    public override string ToString()
    {
        return $"Metody w {typeof(T).Name}:{Environment.NewLine}{string.Join(',', metody)}{Environment.NewLine}";
    }
}
jarekr000000 napisał(a):

w teorii, żeby np. wczytac plik konfiguracyjny i na jego podstawie ustawić zmienne w statyczne.

w praktyce to po prostu bardzo zły pomysł. W zasadzie nie spotykam użycia w kodzie od dawna (kiedyś bywało).

Bardzo złym pomysłem jest w ogóle czytanie pliku w konstruktorze, a ze statycznością nie ma to żadnego związku.

1
somekind napisał(a):
jarekr000000 napisał(a):

w teorii, żeby np. wczytac plik konfiguracyjny i na jego podstawie ustawić zmienne w statyczne.

w praktyce to po prostu bardzo zły pomysł. W zasadzie nie spotykam użycia w kodzie od dawna (kiedyś bywało).

Bardzo złym pomysłem jest w ogóle czytanie pliku w konstruktorze, a ze statycznością nie ma to żadnego związku.

Uff, jak dobrze, że wczytuję plik w inicjalizatorze statycznego pola, a nie w statycznym konstruktorze.

0

@jarekr000000: @AnyKtokolwiek @somekind
Dlaczego nie należy używać statycznego konstruktora do wczytywania pliku konfiguracyjnego?
W jaki sposób i dlaczego należy wczytywać pliki konfiguracyjne?

@Wibowit Jak wczytujesz to w "inicjatorze" statycznego pola?

Czy jest różnica w przypadku gdy język posiada kompilator lub interpreter?

Czy za pomocą statycznego konstruktora w Pythonie powinienem wczytywać pliki konfiguracyjne?
Zależy mi na silnym typowaniu - spowodowało to trochę problemów.
zamiast używać with file.json as configuration:

Wyobrażam sobie użyć klasy tylko do tego aby ustawić wartości w konfiguracji i jej walidację.

4
Marcin Marcin napisał(a):

Dlaczego nie należy używać statycznego konstruktora do wczytywania pliku konfiguracyjnego?

Bo trudno się obsługuje błędy w statycznym konstruktorze (nie jest ponawiany) i trudno wsadzić tam jakąś bardziej skomplikowaną logikę (bo nie przyjmuje parametrów)

W jaki sposób i dlaczego należy wczytywać pliki konfiguracyjne?

W pierwszej lini maina w normalnym kodzie i potem przekazywac jako parametr wszędzie tam gdzie potrzebujesz. W Scali działa. W Javie bez Springa działa. W Haskellu działa. Więc pewnie nawet w C# zadziała

@Wibowit Jak wczytujesz to w "inicjatorze" statycznego pola?

Wibowit tu raczej kpi bo Java nie ma statycznych konstruktorów tylko statyczne bloki inicjalizacyjne

Czy za pomocą statycznego konstruktora w Pythonie powinienem wczytywać pliki konfiguracyjne?

A Python ma coś takiego? Nie sądzę. No ale zawsze można wyrzeźbić obejście

0
KamilAdam napisał(a):

@Wibowit Jak wczytujesz to w "inicjatorze" statycznego pola?

Wibowit tu raczej kpi bo Java nie ma statycznych konstruktorów tylko statyczne bloki inicjalizacyjne

Tak, zażartowałem sobie. Sorry za wprowadzenie w błąd :)

Natomiast, co do zasady, to co za problem wczytać plik?

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class StaticDisaster {
    interface UnsafeSupplier<T> {
        T get() throws Throwable;
    }

    static <T> T swallowException(UnsafeSupplier<T> supplier) {
        try {
            return supplier.get();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return null;
        }
    }

    static Path filePath = Path.of("temp.txt");

    static {
        try {
            Files.write(filePath, "ala ma kota".getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static String fileContents = swallowException(() -> Files.readString(filePath));

    public static void main(String[] args) throws IOException {
        System.out.println(fileContents);
        Files.delete(filePath);
    }
}

Powyższy kod to oczywiście przykład jak nie należy programować.

3

No paczcie jaki żartowniś

3
Marcin Marcin napisał(a):

@jarekr000000: @AnyKtokolwiek @somekind

Dlaczego nie należy używać statycznego konstruktora do wczytywania pliku konfiguracyjnego?
W jaki sposób i dlaczego należy wczytywać pliki konfiguracyjne?

No mniej więcej tak jak @KamilAdam napisał. Może nie zawsze jest to pierwsza linijka maina, ale gdzieś w miejscu startu aplikacji, a potem dostarczać wszędzie tam, gdzie to potrzebne.

Ja od siebie dodam, że dla mnie konstruktor to jest coś, co ma zbudować obiekt z danych w pamięci i co najwyżej rzucić jakimś ArgumentNullException albo ArgumentOutOfRangeException, a nie jakimiś wyjątkami związanymi z I/O. Jeśli obiekt może zostać zbudowany z danych pliku, to lepiej użyć metody, bo metoda w przeciwieństwie do konstruktora może mieć sensowną nazwę. Np.: var bitmap = Bitmap.FromFile("dupa.bmp") wygląda lepiej niż var bitmap = new Bitmap("dupa.bmp").

1 użytkowników online, w tym zalogowanych: 0, gości: 1