generic 함수를 작성하는데, 기본 값을 생성해줘야 할 때가 있었다. 이 때 사용하게 되는 키워드가 new와 default다. 이 글에서는 class, struct 그리고 enum을 사용할 때 어떤 점을 주의해야 하는지 살펴보도록 하겠다.
new와 default
new는 generic 함수의 제약 조건이다. 해당 제약 조건을 걸면 generic 함수 내에서 new T()와 같은 코드를 사용할 수 있다. 이 제약 조건을 걸었을 경우 struct와 enum은 항상 사용가능하고, class는 구현에 따라 달라지게 된다.
default는 C#의 기본 키워드로 제약 조건이 필요하지도 않고, 다른 많은 곳에서도 사용할 수 있는 기능이다. default를 각 타입에 사용할 경우 아래 표와 같은 값이 생성된다.
typedefault value
class | null |
struct | Struct { fields = default(type)… } |
enum | 0 (가장 처음 나오는 0인 item) |
이제 각 타입의 기본값을 설정할 때 주의할 점을 살펴보도록 하겠다.
class
class는 참조 타입(reference type)이기 때문에 null을 허용한다. 그래서 default를 사용했을 때 값은 항상 null이 된다.
new의 경우 생성자를 하나도 만들지 않은 상태라면, 항상 사용이 가능하다(기본 생성자). 반대로 매개 변수가 있는 생성자만 있을 때는 사용할 수 없다.
using System;
public class ClassDefault1
{
public int item1 { get; set; }
public string item2;
}
public class ClassDefault2
{
public int item1 { get; set; }
public string item2;
public ClassDefault2(int item1Value)
{
item1 = item1Value;
}
}
public class Program
{
public static TRefType GetDefault<TRefType>()
where TRefType : new()
{
return new TRefType();
}
public static void Main(string[] args)
{
var cls = GetDefault<ClassDefault1>();
// ClassDefault1 { item1 = 0, item2 = null }
var cls2 = GetDefault<ClassDefault2>();
// Error CS0310
}
}
struct
struct는 값 타입(value type)이다. 참조가 아니기 때문에 null을 허용하지 않는다.
default의 값은 new 구문으로 생성한 값과 같다.
public struct StructDefault {
public int item1 { get; set; }
public string item2;
public StructDefault(int i) {
item1 = i;
item2 = "";
}
}
var str = default(StructDefault);
var str2 = new StructDefault());
// str, str2 == StructDefault { item1 = 0, item2 = null }
만약 default나 new로 생성하고자 한다면, 각 멤버에 기본 값을 설정해두면 된다.
public struct StructDefault {
public int item1 { get; set; } = 10;
public string item2 = "test";
}
var str = default(StructDefault);
// StructDefault { item1 = 10, item2 = "test" }
enum
enum은 struct와 같은 값 타입이다. default와 new를 사용할 때 항상 '(E)0’이 설정된다.
public enum EnumDefault1 {
Item1,
Item2,
Item3,
Item4,
}
public enum EnumDefault2 {
Item1, // 0
Item2, // 1
Item3 = 0,
Item4, // 1
}
public enum EnumDefault3 {
Item1 = 1,
Item2, // 2
Item3, // 3
Item4, // 4
}
var enm1 = default(EnumDefault1);
// EnumDefault1.Item1
var enm2 = default(EnumDefault2);
// EnumDefault2.Item1
var enm3 = default(EnumDefault3);
// 0
var newEnm = new EnumDefault1();
// EnumDefault1.Item1
EnumDefault3은 항목 중 0인 값이 없기 때문에 상수 0이 들어가게 된다. 이런 경우가 생길 수 있기 때문에 MSDN에서는 상수 0인 값이 항상 enum에 포함되는 것을 권장한다.
만약, enum만 사용가능한 generic 함수를 만들고 싶다면 아래와 같은 코드를 작성하면 된다.
public TEnum EnumDefault<TEnum>()
where TEnum : struct, IConvertible
{
if (!typeof(TEnum).IsEnum)
{
throw new ArgumentException("TEnum must be an enumerated type");
}
return default(TEnum);
}
다만 이런 형태의 코드를 사용할 경우, 컴파일러 오류로 체크되지 않을 수 있다.
'프로그래밍 언어 > C#' 카테고리의 다른 글
[C#] 하나의 클래스의 모든 상속클래스 (자식클래스) 가져오기 (0) | 2023.09.21 |
---|---|
[C#] event (이벤트) 개념 (0) | 2023.09.18 |
[C#] 제네릭 메서드(Generic Method) 널(Null) 반환 방법 (0) | 2023.08.23 |
[C#] 자료형(Data Type)의 기본 값(default) 연산자 (0) | 2023.08.23 |
[C#] 리플렉션 (Reflection) 예시 (0) | 2023.08.23 |