일반적으로, 구조체는 값 그 자체를 나타내기 때문(=참조 형식이 아니기 때문)에 'Nothing(null)' 이 될 수 없습니다.

GetType 키워드를 사용하여 구조체의 형식을 가져온 후에 Type.IsValueType 속성을 봐도 구조체는 값 그 자체이기 때문에 IsValueType 속성의 값은 True로 나오게 됩니다. 이런 값 형식에 대해서는 어떻게 Nothing인지의 여부를 확인할까요?



Structure MyStructure
    Public MyField1 As Int32
    Public Sub MyMethod()
    End Sub
    Public Property MyProperty As Int32
End Structure
Class MyCustomClass
    Public MyField1 As Int32
    Public Sub MyMethod()
    End Sub
    Public Property MyProperty As Int32
End Class


일단, 한가지 예를 들기 위해서.. 위처럼 자료형을 선언하였고, 예제 코드를 이렇게 작성하였습니다.

Dim ms As MyStructure, _
    mc As MyCustomClass

ms.MyMethod()
mc.MyMethod()

이 코드는 어떤 결과를 가져올까요?

구조체(MyStructure)의 경우 값 그 자체이므로 개체를 생성할 필요가 없습니다. 값이기 때문이지요.

그래서 구조체의 MyMethod 메서드 호출, 즉! ms.MyMethod() 명령은 아무런 문제 없이 실행이 됩니다.

하지만, 클래스나 인터페이스는 참조 형식이기 때문에, 개체가 생성되지 않으면 문제가 발생합니다.

흔히 말해서, 변수를 초기화를 하지 않은 상태에서 사용한 것이죠. (엄밀히 따지면, VB에선 변수 선언과 동시에 초기값으로 값이 설정되긴 하지만.. 이 설명은 C에 비유해서 한 것입니다)

그래서 MyCustomClass의 MyMethod 메서드 호출, mc.MyMethod() 명령은 'NullReferenceException' 예외를 발생시키게 됩니다. 값 형식이 아닌 참조 형식인데, 변수에 대한 초기화가 이뤄지지 않았기 때문이죠.

그래서, 참조 형식에 대한 Nothing 값을 검사하는 것은 매우 간단합니다.


VB에서 지원하는 IsNothing 메서드를 사용하거나, Is 혹은 IsNot 연산자를 이용하여 Nothing 여부를 확인하면 됩니다.

Expression Is Nothing
Expression IsNot Nothing


Is, IsNot 연산자는 '참조 형식'을 대상으로만 사용할 수가 있습니다. 값 형식에 대해서 사용하려는 경우 컴파일 오류가 발생하게 됩니다.


첫 번째 표현의 경우 표현식(Expression)이 Nothing(null) 이면 True를 반환하고,

두 번째 표현의 경우 표현식(Expression)이 Nothing(null) 이 아니면 True를 반환합니다.


C/C++, C# 등에선 이렇게 간단하게 표현이 됩니다.

Expression == null
Expression != null


그럼 IsNothing 이란 메서드를 한번 살펴보도록 하겠습니다.

public static bool IsNothing(object Expression)
{
    return Expression == null;
}


C# 으로 바뀌었는데, VB로 바꿔보면 'Return Expression Is Nothing' 과 같게 됩니다.

하지만 이 메서드엔 아주 심각한 문제가 하나 있습니다. 애초에 Nothing(null) 을 검사하는 대상이 참조 형식이라고 생각을 해서 그런지, '값 형식'을 IsNothing 메서드의 매개 변수로 전달하게 되면 무조건적으로 False를 반환해버립니다.

이걸 문제라고 보기엔 확실히 틀린 말이긴 합니다. 값 형식이기 때문에 Nothing(null) 값을 대입한다 하더라도 기본 값이 들어가게 되기 때문이죠. 하지만, IsNothing 메서드만으로 Nothing(null) 값을 확인하기엔 불가능한 점이 있습니다.

바로 이런 코드에서 입증이 되는 셈이죠.

Public Shared Function GetValueTypeNull(ByVal treatAsNull As BooleanAs MyStructure
    If treatAsNull Then Return Nothing
    Return New MyStructure()
End Function


이 코드에서는 분명 매개 변수의 값이 True 이면 Nothing 을 반환하고, 그 외의 경우 구조체를 초기화하여 반환해주고 있습니다. 


과연 정말일까? 코드는 아래와 같이 작성되었습니다.

Module Main
    Structure MyStructure
        Public MyField1 As Int32
        Public Sub MyMethod()
        End Sub
        Public Property MyProperty As Int32
    End Structure
    Public Sub Main()
        Console.WriteLine("IsNothing Method Test Result")
        Console.WriteLine("1. GetValueTypeNull(True) : {0}", IsNothing(GetValueTypeNull(True)))
        Console.WriteLine("2. GetValueTypeNull(False): {0}", IsNothing(GetValueTypeNull(False)))
        
        Console.ReadKey(True)
    End Sub
    Public Function GetValueTypeNull(ByVal treatAsNull As BooleanAs MyStructure
        If treatAsNull Then Return Nothing
        Return New MyStructure()
    End Function
End Module

이 코드의 결과는 어떨까요?


역시나 둘다 False가 나오는 것을 알 수 있습니다.

그럼 도대체 어떤 방법을 써야 이 글의 주제와 맞는 '값 형식' 도 참조 형식처럼 사용할 수 있는 걸까요?

정답은 매우 간단합니다. 자료형 뒤에 물음표(?, Question Mark)를 붙이는 것입니다.

정말 간단하지 않나요?

Dim ms As MyStructure?


그럼 여기서 사용된 물음표의 역할은 무엇일까요?

바로 Nullable(Of T) 구조체입니다!

물음표를 붙이게 되면 자동적으로 해당하는 자료형을 인식해서 MyStructure? 이란 구문을 Nullable(Of MyStructure) 으로 바꿔주는 것이지요.

그럼 이게 정말로 효과가 있는지 확인해볼까요?

Module Main
    Structure MyStructure
        Public MyField1 As Int32
        Public Sub MyMethod()
        End Sub
        Public Property MyProperty As Int32
    End Structure
    Public Sub Main()
        
        Dim ms As MyStructure?
        
        Console.WriteLine("IsNothing Method Test Result")
        ' Step 1. Pass not initialized object (In here, we're using Nullable(Of T))
        Console.WriteLine("1. IsNothing (Un-initialized structure): {0}", IsNothing(ms))
        
        ' Now, Initialize the structure.
        ms = New MyStructure()
        Console.WriteLine("1. IsNothing (Initialized structure)   : {0}", IsNothing(ms))
        
        Console.ReadKey(True)
    End Sub
End Module


이 코드의 결과는 ?!?!?!


짜쟌!!! 값 형식임에도 불구하고 IsNothing 메서드를 사용하였는데 True를 반환하는 것을 볼 수 있습니다.

Nullable 형식은 값 형식의 유효성 검사가 반드시 행해져야 할 때, 유용하게 사용될 수 있습니다.

그리고, 아래 코드에서의 선언은 서로 동일한 형식으로 됩니다.

Dim ms1 As MyStructure?
Dim ms2 As Nullable(Of MyStructure)


그리고 Nullable(Of T) 형식에 대한 MSDN 문서 페이지입니다.

Nullable(Of T) from MSDN


.NET에는 참 다양한 형식들이 많고, 다양한 기능을 하는 메서드들도 많이 있습니다.

이렇게 숨어있는 유용한 형식들을 하나 하나 찾다보면, 언젠가는 프로그래밍을 잘하게 될 수 있지 않나 생각해봅니다.



긴 글 읽어주셔서 감사합니다!


+ Recent posts