C#은 정적 타입을 쓰는 언어로 형식 검사가 매우 엄격한 언어다. 파이썬과는 다르게 변수 선언시 형식에 대해서 지정해줄 필요가 있으며 이런 형식 지정을 통해서 잘못된 연산을 미리 방지하는 순기능이 있다.
자바스크립트 같이 컴파일러에서 형식을 추론해서 지정하는 언어의 경우에는 문자열과 숫자열간의 연산이 이루어지기도 하지만 C#같이 강력한 형식의 언어는 사전에 방지해준다.
C#의 모든 형식은 System.Object에서 파생되며 이를 상속받아 쓴다.(즉 System.object는 모든 클래스의 기본이 된다) 여기서 아래의 2개의 형태로 나뉘어진다.
값 형식 - 값을 담고있는 형식으로써 흔히 생각하는 변수. System.ValueType에서 상속되며 기본적으로 열거형을 빼면 구조체 형식에 기반한다.
참조 형식 - 값이 있는곳의 위치를 저장한 형식으로써 클래스,인터페이스,대리자등이 속한 형식. 문자열과 배열도 할당값이 값형식이라고 해도 실제로는 참조형식으로 구성되어있다. 따라서 참조형식을 값형식처럼 쓸수도 있다. 또한 참조형식은 주소값을 가지기 때문에 별도로 값을 생성해서 넘겨줘야 안전하게 값을 보내줄수 있다.

↑실제 C#의 형식이 어떻게 구성되어 있는가에 대한 이미지.
값 형식의 경우 입력되는 값의 형태에 대해서 추가로 형식문자를 추가해서 타입에 대해서 서술하는것이 가능하며 이를 리터럴 형식이라고 부른다.
값형식과 참조형식은 각자 사용하는 메모리또한 다르다. 일반적으로 선언된 값형식은 스택에 저장되며 실행되는 코드블럭이 끝나면 스택에서 제거된다. 참조형식은 스택에 주소값이 저장되며 실제 값을 힙에 저장시킨다. 코드가 끝나면 스택에 저장된 값은 자동으로 지워지며 힙에 저장된 실제 값은 후에 가비지 컬렉션이 진행되면서 제거된다.
이렇게 만들어진 변수는 처음 작성할때 비워놓거나 특정값을 입력해서 초기화 시켜놓을수 있다. 한번 특정 형식으로 선언된 변수는 다른 형식으로 바꿀수 없다.
C#은 강력한 정적타입 언어이긴 하지만 추론 타입을 지원한다. 형식이 Var일 경우 컴파일러가 컴파일 단계에 들어갈 경우 입력값에 따라서 적절한 타입으로 변환해서 실행시켜준다. 따라서 실제 실행시에는 입력된 값에 맞는 타입으로 나온다.
만약 생성된 이후에 값을 변경해줘야 된다면 형변환을 이용해서 바꿔줘야 된다. 형변환은 암시적으로 이루어질수도 있으며 캐스팅을 통해서 명시적으로 바꿔줄수 있다. 특정 형식에 (바꿀 형식)변수 로 작성할경우 해당 형식으로 바뀌는걸 명시적 형변환(캐스팅)이라고 한다.
한꺼번에 많은 자료를 저장하려면 배열을 쓰면 된다. C#의 모든 배열은 object형식에서 상속되며 C/C++이 메모리 주소를 저장하고있는것과 다르게 개체로써 존재한다. 따라서 배열을 만들 경우 new키워드를 통해 개체를 할당해야되며 new키워드 없이 배열을 만들경우 컴파일러가 암시적으로 생성해준다.
배열을 생성할때 배열의 차원을 늘려서 다차원 배열을 생성하는것 또한 가능하다. 배열의 차원을 여러개를 지정해줄 경우 다차원 배열이 생성되며 이를 명시적으로 지정해주거나 암시적으로 만들어줄수 있는데 일반적으로 3차원 이상의 배열은 가급적이면 생성하지 않는것이 좋다.
출저