C#

C#] Value VS Reference Types

Fastlane 2024. 2. 1. 14:16
728x90
반응형

C# data types 분류에 대해 살펴보자. value types과 reference types의 차이점도 살펴보자. 

C#은 strongly-typed 언어이다. 각 변수가 특정 type을 갖고 있고, 각 type은 value type 또는 reference type이 될 수 있다. 

Value Types

값 타입 변수는 데이터를 직접적으로 갖고 있고, System.ValueType으로부터 상속받은 struct keyword를 사용하여 지정된다. 

  • Numeric types
  • bool, char types
  • Date types

내장 값 타입을 제외하고, struct keyword를 사용해서 custom 값 타입을 정의할 수 있다. fields 또는 properties로 값 타입 또는 참조 타입을 가질 수 있다. 

public struct ValueTypeRectangle
{
    public int Length { get; set; }
    public int Width { get; set; }
    public Shape MyShape { get; set; }

    public int Area()
    {
        int area = Length * Width;
        Console.WriteLine($"length = {Length}");
        Console.WriteLine($"width = {Width}");
        Console.WriteLine($"shape = {MyShape.Name}");
        Console.WriteLine($"area = {area}");

        return area;
    }
}

public class Shape
{
    public string Name { get; set; }
}

struct 키워드를 사용해서 ValueTypeRectangle type을 선언했다. reference type인 Shape type을 갖는다. 

Value Type Assignment

var firstRectangle = new ValueTypeRecta
{
    Length = 10,
    Width = 10,
    MyShape = new Shape { Name = "Square" }
};
                                       
var secondRectangle = firstRectangle;
                                       
firstRectangle.Length = 20;
firstRectangle.Width = 20;
firstRectangle.MyShape.Name = "Circle";

Console.WriteLine("First Rectangle area ->");
firstRectangle.Area();
Console.WriteLine("Second Rectangle area ->");
secondRectangle.Area();

//Output:
//First Rectangle area ->
//length = 20
//width = 20
//shape = Circle
//area = 400
//Second Rectangle area ->
//length = 10
//width = 10
//shape = Circle
//area = 100

value type을 다른 변수에 할당할 때, value type members의 값이 새 object로 복사된다. 원래 object의 memeber 중 하나를 변경해도 다른 object에 영향을 주지 않는다. 

Reference Type Member 변경

Shape name을 Circle  에서 Square로 변경하면 새 object의 Shape name도 변경된다. value type members와 다르게, memory에 shape object를 생성한 것이 아닌, reference를 복사한 것이다. 양 object reference는 동일한 instance이다. 

 

결론적으로, value type을 다른 변수에 할당할 때, value type의 새로운 instance가 생성되고 모든 value type members가 순차적으로 복사된다. 반면, reference type은 references만 복사된다. 

 

Value Type 기본 값

  • byte: 0
  • bool: false
  • char: ‘\0’
  • double: 0.0
  • float: 0.0f
  • int: 0
  • DateTime: 01/01/0001 00:00:00

Value type은 Nullable로 선언되지 않는 한, null이 될 수 없다. 

Reference Types

value type과는 반대로, reference type의 변수는 데이터의 reference를 갖고 있다. value의 pointer라고 생각할 수 있다. 

 

  • string
  • dynamic
  • object
  • delegate
  • class
  • interface

Reference Type Assignment

public class ReferenceTypeRectangle
{
    public int Length { get; set; }
    public int Width { get; set; }

    public int Area()
    {
        int area = Length * Width;
        Console.WriteLine($"length = {Length}");
        Console.WriteLine($"width = {Width}");
        Console.WriteLine($"area = {area}");

        return area;
    }
}

 

 

var firstRectangle = new ReferenceTypeRectangle()
{
    Length = 10,
    Width = 10
};
                                                 
var secondRectangle = firstRectangle;
                                                 
firstRectangle.Length = 20;
firstRectangle.Width = 20;

Console.WriteLine("First Rectangle area ->");
firstRectangle.Area(); 
Console.WriteLine("Second Rectangle area ->"); 
secondRectangle.Area();

//output
//First Rectangle area ->
//length = 20
//width = 20
//area = 400
//Second Rectangle area ->
//length = 20
//width = 20
//area = 400

reference type 변수를 할당하면, 단지 새로운 변수에 reference를 복사한 것이다. 어떠한 new object도 초기화하지 않았다. 두 reference가 메모리의 동일한 object를 가리키므로, 하나를 수정하면 다른 하나도 변경된다. 

Reference Type 기본 값

reference type 변수의 기본값은 null이다. reference type 변수를 초기화없이 선언했다면, instance를 할당하지 않는 한 null이다. 

Memory Allocation

.NET에는 stack, heap이라는 2종류의 메모리가 있다. 모든 reference type은 heap에 위치한다. heap에 있는 object의 reference를 갖는 변수에 대해서는 stack에 위치한다. 

 

Reference type

Reference Example의 메모리 위치이다. 

firstRectangle과 secondRectangle을 reference type으로 선언했다. properties가 value type(int)라 하더라도 reference type안에 있기 때문에 heap에 위치한다. 

 

Value type

runtime은 value type을 어디에 선언되었는지에 따라 stack 또는 heap에 저장한다.  value type이 method나 class member로 선언하면 stack에 저장된다. 하지만 reference type의 일부로 선언되거나 List<int>와 같은 collection으로 선언되면 heap에 위치한다. 

 

MyShape property는 heap에 위치하고 reference는 stack에 위치한다. Shape type이 reference type인 class이기 때문이다. 

 

위에 언급한 것처럼 MyShape reference는 heap의 동일한 object를 가리킨다. 따라서 하나의 instance의 Shape의 Name을 변경하면 다른 것도 변경된다. 

 

Value and Reference Types 함수 Arguments

Value와 reference types이 함수에 arguments로 전달될 때, 다르게 동작한다. value type을 전달하면 copy를 전달한 것이다. 호출된 함수 내부에서 value type object의 변경사항이 호출한 함수에 영향을 주지 않는다. 양쪽 별개의 copies를 사용했기 때문이다. reference type을 전달하면 reference의 copy를 전달한 것이다. 호출된 함수 내부에서 argument가 변경되면, 호출한 함수의 instance에도 영향을 준다. 

Value, Reference Type의 성능 영향

value, reference type 사용에 성능의 차이가 있다. 

 

value type이 stack에 위치할 때 런타임 초기화 시, heap에 있는 referencey type의 초기화보다 빠르다. 반면에, method argument로 전달될 때, value type은 복사되기 때문에 용량이 큰 value-type objects는 메모리 사용량을 증가시킬 수 있다. 

 

앱 사용과, 성능에 따라 value와 reference type 중 신중히 선택해야 한다. 

Boxing and Unboxing

Boxing은 value type을 object type으로 변환하는 것이다. Unboxing은 object type을 value type으로 변환하는 것이다. 

int number = 10;
                                       
object boxedNumber = number;
int unboxedNumber = (int)boxedNumber;
                                       
Assert.AreEqual(number, unboxedNumber);

unboxing은 암시작 변환이기 때문에, cast를 사용해 변환해야 한다. 

Boxing과 unboxing은 비용이 든다. 

 

728x90
반응형