Jak używać zmiennych globalnych w C #?

101

Jak zadeklarować zmienną, aby każda klasa (* .cs) miała dostęp do jej zawartości bez odwołania do instancji?

Mas Ajum
źródło

Odpowiedzi:

123

W C#nie można zdefiniować prawdziwych zmiennych globalnych (w tym sensie, że nie należą one do żadnej klasy).

Biorąc to pod uwagę, najprostsze podejście, jakie znam, aby naśladować tę funkcję, polega na użyciu w static classnastępujący sposób:

public static class Globals
{
    public const Int32 BUFFER_SIZE = 512; // Unmodifiable
    public static String FILE_NAME = "Output.txt"; // Modifiable
    public static readonly String CODE_PREFIX = "US-"; // Unmodifiable
}

Następnie możesz pobrać zdefiniowane wartości w dowolnym miejscu kodu (pod warunkiem, że jest częścią tego samego namespace):

String code = Globals.CODE_PREFIX + value.ToString();

Aby poradzić sobie z różnymi przestrzeniami nazw, możesz:

  • zadeklaruj Globalsklasę bez dołączania jej do konkretnej namespace(aby została umieszczona w globalnej przestrzeni nazw aplikacji);
  • wstaw odpowiednią dyrektywę using do pobierania zmiennych z innego namespace.
Tommaso Belluzzo
źródło
@Zarathos czy klasa też musi być statyczna?
kosnkov
4
Cóż, nie jest to konieczne, ale nie rozumiem, dlaczego należy go utworzyć.
Tommaso Belluzzo
Jeśli musisz utworzyć instancję zgodnie z definicją, która nie jest już „globalna”, nie jest częścią stanu aplikacji
Viking
Cześć, jaka byłaby różnica, gdybym nie wpisał statycznego słowa kluczowego w klasie? Zrobiłem tylko statyczny ciąg FILE_NAME, próbowałem i nadal działał.
Tomer Cahal
1
Bez statycznego atrybutu Twoja klasa będzie mogła zostać utworzona (Globals g = new Globals ()). Nie zmienia zachowania zadeklarowanych wewnątrz zmiennych statycznych, ale nie wygląda to na zbyt użyteczne.
Tommaso Belluzzo
74

Nie ma czegoś takiego jak zmienna globalna w C #. Kropka.

Jeśli chcesz, możesz mieć statycznych członków:

public static class MyStaticValues
{
   public static bool MyStaticBool {get;set;}
}
Federico Berasategui
źródło
Chociaż zgadzam się, czy mógłbyś rozszerzyć, dlaczego w C # nie ma czegoś takiego jak zmienna globalna? Próbowałem wymyślić dobry powód, dla którego tego samego staticprzykładu, który podałeś, nie można tak naprawdę uznać za zmienną globalną.
cregox
3
@cawas, ponieważ sama koncepcja „zmiennej globalnej” (wiszącej znikąd, unoszącej się w zawieszeniu, nienależącej do żadnej klasy) jest sprzeczna z samą naturą OOP. a C # jest ściśle zorientowany obiektowo.
Federico Berasategui
Tak, z tym się zgadzam. Ale tworząc ten statyczny element członkowski, właśnie utworzyłeś rodzaj globalnej zmiennej. Czym to się różni od globalnej zmiennej, którą powiedziałeś, że nie istnieje? Chciałbym zobaczyć praktyczny przykład.
cregox
1
Czuję, że albo unikasz mojego pytania, albo nie jestem jasny. Ale już otrzymałem odpowiedź. Tutaj: stackoverflow.com/a/20010543/274502
cregox
7
Teraz zdaję sobie sprawę, że miałem na myśli to, że statyczne elementy członkowskie są koncepcyjnie i praktycznie globalnymi zmiennymi (może z wyjątkiem tego sterty , co ma znaczenie tylko wtedy, gdy piszesz niebezpieczny kod lub wykonujesz jakiś rodzaj ciężkiej współpracy z niezarządzanym kodem ). Więc nie wiem, dlaczego ktoś miałby mówić „ nie ma czegoś takiego jak zmienna globalna w csharp ”. Bardzo mnie to zdezorientowało.
cregox
23

Najpierw sprawdź, czy naprawdę potrzebujesz zmiennej globalnej, zamiast używać jej rażąco, bez uwzględnienia architektury oprogramowania.

Załóżmy, że przejdzie test. W zależności od zastosowania, Globals mogą być trudne do debugowania z warunkami wyścigu i wieloma innymi „złymi rzeczami”, najlepiej jest podejść do nich z punktu, w którym jesteś przygotowany na takie złe rzeczy. Więc,

  1. Zawiń wszystkie takie zmienne globalne w jedną staticklasę (w celu ułatwienia zarządzania).
  2. Mają Właściwości zamiast pól (= 'zmienne'). W ten sposób masz pewne mechanizmy rozwiązywania problemów z jednoczesnym zapisem do Globals w przyszłości.

Podstawowy zarys takiej klasy wyglądałby następująco:

public class Globals
{
    private static bool _expired;
    public static bool Expired 
    {
        get
        {
            // Reads are usually simple
            return _expired;
        }
        set
        {
            // You can add logic here for race conditions,
            // or other measurements
            _expired = value;
        }
    }
    // Perhaps extend this to have Read-Modify-Write static methods
    // for data integrity during concurrency? Situational.
}

Użycie z innych klas (w tej samej przestrzeni nazw)

// Read
bool areWeAlive = Globals.Expired;

// Write
// past deadline
Globals.Expired = true;
Sid
źródło
4

Przydatną funkcją jest do tego using static

Jak powiedzieli inni, musisz utworzyć klasę dla swoich globali:

public static class Globals {
    public const float PI = 3.14;
}

Ale możesz to zaimportować w ten sposób, aby nie zapisywać już nazwy klasy przed jej właściwościami statycznymi:

using static Globals;
[...]
Console.WriteLine("Pi is " + PI);
Zotta
źródło