Podobnie jak w Javie i C/C++, w języku C# wszystkie zmienne muszą być przed użyciem zadeklarowane, a zatem jest to również język ze ścisłą kontrolą typu.
W C#, jak w Javie, zmienne wszystkich typów mają ustaloną reprezentację i nie ma tu, jak w C/C++, żadnych dowolności. W odróżnieniu jednak od Javy, liczbowe typy całkowite występują, tym razem właśnie jak w C++, w obu formach: ze znakiem i bez znaku. Zmienne liczbowe są wszystkie formalnie strukturami wywiedzionymi z klasy System.ValueType. Każdemu typowi C# odpowiada klasa z przestrzeni nazw System (odpowiadającej pakietowi java.lang z Javy). Nazywamy je strukturami a nie obiektami, gdyż w C# istnieją, prócz klas i obiektów właśnie struktury. Są one wzorowane na strukturach znanych z języka C, o których będziemy jeszcze mówić. Na razie zapamiętajmy, że klasa ValueType tak „opakowuje” struktury odpowiadające liczbom, aby ich użycie było zgodne z semantyką wartości, a nie odniesień (referencji). Zatem zmiennych liczbowych używamy w C# tak samo jak w Javie czy C/C++. Deklarując zmienne można używać zarówno nazw klas z przestrzeni System jak i ich synonimów bardziej przypominających nazwy znane nam z Javy czy C/C++. Tak więc np. deklaracja
System.Int32 k = 32;jest równoważna
int k = 32;W poniższej tabeli zamieszczone są podstawowe typy danych w C# wraz z ich synonimami z przestrzeni nazw System.
Podobnie jak w Javie, typ logiczny (bool, czyli System.Boolean) jest całkowicie samodzielnym typem i nie ma nic wspólnego z typami całkowitymi.
Znaki (zmienne typu char, czyli System.Char) są reprezentowane przez całkowite kody Unicode'u, jak w Javie.
Język C#, tak jak i Java, przejął też z języka C/C++ typ wyliczeniowy.
Wyliczenia i zmienne typów wyliczeniowych definiuje
się podobnie jak w C/C++, choć należy pamiętać o obiektowości
C#. Otóż wyliczenia stanowią osobny typ obiektowy (wszystkie są
wywiedzione z klasy
System.Enum) i wobec tego można je
definiować poza wszystkimi klasami (podobnie jest w Javie).
Do poszczególnych elementów trzeba wtedy oczywiście odnosić się
przez nazwy kwalifikowane nazwą typu, jak w poniższym przykładzie:
      1.  using System;
      2.  
      3.  enum Jezyk { Francja, Niemcy, Austria, Anglia }
      4.  
      5.  class DzienDobry {
      6.      public static string powiedz(Jezyk jez) {
      7.          switch (jez) {
      8.              case Jezyk.Francja:
      9.                  return "Bonjour";
     10.              case Jezyk.Niemcy:
     11.              case Jezyk.Austria:
     12.                  return "Guten Tag";
     13.              default:
     14.                  return "Hi";
     15.          }
     16.      }
     17.  }
     18.  
     19.  class Enumer {
     20.      public static void Main() {
     21.          Jezyk jezyk = Jezyk.Francja;
     22.          Console.WriteLine(DzienDobry.powiedz(jezyk));
     23.          jezyk = Jezyk.Niemcy;
     24.          Console.WriteLine(DzienDobry.powiedz(jezyk));
     25.          Console.WriteLine(DzienDobry.powiedz(Jezyk.Anglia));
     26.      }
     27.  }
    Bonjour
    Guten Tag
    Hi
Podobnie jak w Javie, w C# nie istnieje arytmetyka wskaźników. Ich rolę pełnią odniesienia, nazywane referenecjam, które jednak, tak jak w Javie, implementacyjnie i koncepcyjnie są bliższe wskaźnikom niż referencjom w C++.
T.R. Werner, 21 lutego 2016; 20:17