Section 39.5: 생성자에서 다른 생성자 호출하기

public class Animal { public string Name { get; set; } public Animal(): this("Dog") {} public Animal(string name) { Name = name; } } var dog = new Animal(); // dog.Name 은 기본값인 "Dog" 으로 설정될 것이다. var cat = new Animal("Cat"); // cat.Name 은 "Cat" 으로 설정되며, 인자가 없는 생성자는 이때 호출되지 않는다.
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 39.4: Static 생성자 강제 호출하기

Static 생성자는 해당 타입이 최초로 사용되기 전에 불리는 것을 보장하고 있긴 하지만, 때에 따라 이를 강제로 호출하는 것이 유용한 경우가 있을 수 있다. RuntimeHelpers 클래스는 이를 위한 지원 기능을 제공하고 있다:

using System.Runtime.CompilerServices; // ... RuntimeHelpers.RunClassConstructor(typeof(Foo).TypeHandle);

유의점: 생성자만이 아니라 모든 static 초기화 (예를 들어 필드 초기자 (initializer) 등) 과정이 수행될 것이다.

사용 가능한 예: UI 응용 프로그램의 초기 splash 화면에서 초기화를 수행한다거나 Unit Test 에서 static 생성자가 실패하지 않음을 보장하는 작업 등.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 39.3: 기본 생성자

특정 타입이 아래와 같이 생성자 없이 정의되었다면:

public class Animal { }

컴파일러는 아래 코드에 상응하는 기본 생성자를 자동으로 만들어 주게 된다:

public class Animal { public Animal() {} }

어떠한 형식이건, 생성자가 따로 정의되는 경우 기본 생성자는 만들어지지 않을 것이다. 만약 아래와 같이 타입 정의가 이루어진 경우라면:

public class Animal { public Animal(string name) {} }

Animal 클래스는 선언된 해당 생성자를 통해서만 생성이 가능할 것이다.

// 아래 코드는 유효하다 var myAnimal = new Animal("Fluffy"); // 아래 코드는 컴파일이 되지 않는다 var unnamedAnimal = new Animal();

위의 두번째 예제에서, 컴파일러는 아래와 같은 에러 메시지를 출력해 줄 것이다:

'Animal' does not contain a constructor that takes 0 arguments

만약 특정 클래스에 파라미터가 없는 생성자와 있는 생성자 두가지를 모두 제공하고자 한다면, 두 생성자를 모두 명시적으로 구현하여야 한다.

public class Animal { public Animal() {} //기본 생성자에 상응하는 생성자 public Animal(string name) {} }

파라미터 없는 생성자를 제공하지 않는 다른 클래스를 확장 (extend) 하는 클래스의 경우, 컴파일러는 기본 생성자를 만들어 줄 수 없다. 예를 들어, 아래와 같은 Creature 클래스가 있다고 가정한다면:

public class Creature { public Creature(Genus genus) {} }

class Animal : Creature {} 와 같이 기술된 Animal 클래스는 컴파일이 되지 않을 것이다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 39.2: 싱글톤 생성자 패턴

public class SingletonClass { public static SingletonClass Instance { get; } = new SingletonClass(); private SingletonClass() { // 필요한 생성자 관련 코드를 이곳에 위치시킨다 } }

위와 같은 패턴 사용 시, 생성자가 private 으로 선언되어 있으므로, SingletonClass 를 사용하는 코드에서 새로운 인스턴스를 임의로 생성할 수 없게 된다. SingletonClass 의 단일 인스턴스를 접근하기 위한 유일한 방법은 바로 SingletonClass.Instance static 속성을 사용하는 것이다.

Instance 속성은 C# 컴파일러가 자동 생성하는 static 생성자에 의해 할당된다. .NET 런타임은 이 static 생성자가 Instance 속성이 최초로 읽히기 전에 반드시 한번 실행됨을 보장해준다. 그러므로, 모든 동기화 및 초기화 관련 세부사항은 .NET 런타임에 의해 처리된다.

유의할 점은, 만약 static 생성자 실행이 실패할 경우, 이 Singleton 클래스는 해당 앱 도메인의 실행 기간 전체에 걸쳐 영구적으로 사용 불가능한 상태가 될 것이라는 점이다. 또한, 이 static 생성자는 Instance 에 대한 첫번째 접근시점에 맞추어 실행됨이 보장되는 것은 아니며, 그보다 더 빠른 시점에 불리게 될 것이다. 이는 초기화가 확정된 시점에 수행되지 않게됨을 의미한다. 실제적인 사례의 경우, JIT 는 보통 static 생성자를 Instance 에 대한 참조가 일어나는 메소드의 컴파일 시점 (실행 시점이 아닌) 에 호출하게 된다. 이는 성능 최적화를 위함이다.

"43: 싱글톤 구현" 페이지에 싱글톤 패턴 을 구현하는 다른 방법들이 소개되어 있다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 39.1: Static 생성자

static 생성자 (constructor) 는 해당 타입의 인스턴스가 최초로 초기화되거나, static 클래스 멤버나 static 메소드가 최초로 호출될 때 수행된다. static 생성자는 멀티스레드 환경에서도 안전하게 수행된다 (thread safe). static 생성자는 일반적으로 다음과 같은 경우에 사용된다:

  • static 한 상태를 초기화한다. 이 상태는 동일 클래스의 각기 다른 인스턴스간에 공유되는 상태값이다.
  • singleton 을 생성한다.

예제:

class Animal { // * static 생성자는 해당 클래스에 // 최초로 접근할 때 단 한번 실행된다. // * static 생성자는 접근 한정자 (access modifier) 를 가질 수 없다. // * static 생성자는 파라미터를 가질 수 없다 static Animal() { Console.WriteLine("Animal initialized"); } // 클래스의 인스턴스가 생성될 때마다 실행되는 instance 생성자. public Animal() { Console.WriteLine("Animal created"); } public static void Yawn() { Console.WriteLine("Yawn!"); } } var turtle = new Animal(); var giraffe = new Animal();

출력 결과:

Animal initialized Animal created Animal created

Demo 확인하기

해당 클래스에 대한 첫번째 호출이 static 메소드인 경우, instance 생성자 호출 없이 static 생성자만 호출이 될 것이다. 그러나 static 메소드는 어차피 instance 상태값에 접근이 불가능하기에 이러한 현상은 아무런 문제를 유발하지 않는다.

Animal.Yawn();

위 코드는 다음과 같은 결과를 출력할 것이다:

Animal initialized Yawn!

"39.8 static 생성자에서의 예외 발생시의 동작" 항목과 "39.10 Generic static 생성자" 항목도 읽어두는 것을 추천한다.

Singleton 예제:

public class SessionManager { public static SessionManager Instance; static SessionManager() { Instance = new SessionManager(); } }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Chapter 39: 생성자와 종료자 (Finalizer)

생성자 (Constructor) 는 해당 클래스의 인스턴스가 생성될 때 불리는 메소드이다. 이들의 주 역할은 새로운 객체를 사용 가능하고 일관성있는 상태로 만들어주는 것이다.

소멸자 (Destructor) / 종료자 (Finalizer) 는 해당 클래스의 인스턴스가 소멸될 때 불리는 메소드이다. C# 에서 이들이 명시적으로 작성되거나 사용되는 경우는 드물다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.7: 제네릭 타입 인자가 nullable 타입인지 확인하기

public bool IsTypeNullable<T>() { return Nullable.GetUnderlyingType( typeof(T) )!=null; }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.6: Nullable<T> 인자의 기반 (underlying) 타입에 대한 효과적인 사용법

모든 nullable 타입은 generic 타입이다. 또한 모든 nullable 타입은 값 (value) 타입이다.

역주: C# 8.0부터는 nullable reference 타입에 대한 새로운 개념이 추가되었습니다. Microsoft 문서 를 참조하세요.

Reflection 이나 코드 자동생성 목적의 코드를 작성할 때, Nullable.GetUnderlyingType 메소드의 결과를 효과적으로 사용할 수 있는 몇가지 기법을 아래의 코드에서 소개하고 있다:

public static class TypesHelper { public static bool IsNullable(this Type type) { Type underlyingType; return IsNullable(type, out underlyingType); } public static bool IsNullable(this Type type, out Type underlyingType) { underlyingType = Nullable.GetUnderlyingType(type); return underlyingType != null; } public static Type GetNullable(Type type) { Type underlyingType; return IsNullable(type, out underlyingType) ? type : NullableTypesCache.Get(type); } public static bool IsExactOrNullable(this Type type, Func < Type, bool > predicate) { Type underlyingType; if (IsNullable(type, out underlyingType)) return IsExactOrNullable(underlyingType, predicate); return predicate(type); } public static bool IsExactOrNullable < T > (this Type type) where T: struct { return IsExactOrNullable(type, t => Equals(t, typeof (T))); } }

사용 예제:

Type type = typeof (int).GetNullable(); Console.WriteLine(type.ToString()); if (type.IsNullable()) Console.WriteLine("Type is nullable."); Type underlyingType; if (type.IsNullable(out underlyingType)) Console.WriteLine("The underlying type is " + underlyingType.Name + "."); if (type.IsExactOrNullable < int > ()) Console.WriteLine("Type is either exact or nullable Int32."); if (!type.IsExactOrNullable(t => t.IsEnum)) Console.WriteLine("Type is neither exact nor nullable enum.");

출력 결과:

System.Nullable`1[System.Int32] Type is nullable. The underlying type is Int32. Type is either exact or nullable Int32. Type is neither exact nor nullable enum.

참고로, NullableTypesCache 는 아래와 같이 선언되어 있다:

static class NullableTypesCache { readonly static ConcurrentDictionary < Type, Type > cache = new ConcurrentDictionary < Type, Type > (); static NullableTypesCache() { cache.TryAdd(typeof (byte), typeof (Nullable < byte > )); cache.TryAdd(typeof (short), typeof (Nullable < short > )); cache.TryAdd(typeof (int), typeof (Nullable < int > )); cache.TryAdd(typeof (long), typeof (Nullable < long > )); cache.TryAdd(typeof (float), typeof (Nullable < float > )); cache.TryAdd(typeof (double), typeof (Nullable < double > )); cache.TryAdd(typeof (decimal), typeof (Nullable < decimal > )); cache.TryAdd(typeof (sbyte), typeof (Nullable < sbyte > )); cache.TryAdd(typeof (ushort), typeof (Nullable < ushort > )); cache.TryAdd(typeof (uint), typeof (Nullable < uint > )); cache.TryAdd(typeof (ulong), typeof (Nullable < ulong > )); //... } readonly static Type NullableBase = typeof (Nullable < > ); internal static Type Get(Type type) { // 호출 비용이 많이 드는 MakeGenericType 메소드 호출을 지양한다 return cache.GetOrAdd(type, t => NullableBase.MakeGenericType(t)); } }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

+ Recent posts