Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 15개 있습니다.)

C# 7.2 - 스택에만 생성할 수 있는 값 타입 지원 - "ref struct"

C# 7.2 (1) - readonly 구조체
; https://www.sysnet.pe.kr/2/0/11524

C# 7.2 (2) - 메서드의 매개 변수에 in 변경자 추가
; https://www.sysnet.pe.kr/2/0/11525

C# 7.2 (3) - 메서드의 반환값 및 로컬 변수에 ref readonly 기능 추가
; https://www.sysnet.pe.kr/2/0/11526

C# 7.2 (4) - 3항 연산자에 ref 지원(conditional ref operator)
; https://www.sysnet.pe.kr/2/0/11528

C# 7.2 (5) - 스택에만 생성할 수 있는 값 타입 지원 - "ref struct"
; https://www.sysnet.pe.kr/2/0/11530

C# 7.2 (6) - Span<T>
; https://www.sysnet.pe.kr/2/0/11534

C# 7.2 (7) - private protected 접근자 추가
; https://www.sysnet.pe.kr/2/0/11543

C# 7.2 (8) - 숫자 리터럴의 선행 밑줄과 뒤에 오지 않는 명명된 인수
; https://www.sysnet.pe.kr/2/0/11544

기타 - Microsoft Build 2018 - The future of C# 동영상 내용 정리
; https://www.sysnet.pe.kr/2/0/11536




지난 글에서,

닷넷의 관리 포인터(Managed Pointer)와 System.TypedReference
; https://www.sysnet.pe.kr/2/0/11529

설명한 System.TypedReference는 내부에 "관리 포인터"를 가지고 있으며, 그 특성으로 인해 관리 힙에 놓일 수 없는 타입이라고 했습니다. 이렇게 "스택에만 생성할 수 있는 타입"을 정의할 수 있는 C# 문법이 바로 7.2부터 제공되는 "ref struct"입니다.

C# 7 Series, Part 9: ref structs
; https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/

ref struct 
; https://docs.microsoft.com/ko-kr/dotnet/csharp/reference-semantics-with-value-types

Compile time enforcement of safety for ref-like types [7.2 Proposal]
; https://www.infoq.com/news/2017/06/CSharp-7.2

Compile time enforcement of safety for ref-like types
; https://github.com/VSadov/csharplang/blob/ef68acb505ad1a3310de133ef7af65c2c24da520/proposals/span-safety.md

(위의 링크에서 제목 중에 "ref-like types"라고 불리는 것이 "ref struct"입니다.)

사용 방법은 단순히 "ref struct" 예약어로 타입을 정의하는 식입니다.

ref struct Vector
{
    public int X;
    public int Y;
    public int Z;

    public void Output()
    {
        Console.WriteLine($"{X},{Y},{Z}");
    }
}

"스택에만 생성할 수 있는 타입"이므로 로컬 변수와 매개 변수에 사용할 수 있고, TypedReference와 달리 내부에 "관리 포인터"를 가지고 있지는 않으므로 변수의 반환에서도 (struct의 값 복사 특성으로 인해) "로컬 변수"인 경우 가능합니다.

using System;

ref struct Vector
{
    public int X;
    public int Y;
    public int Z;
}

class Program
{
    // 컴파일 오류: CS8345 Field or auto-implemented property cannot be of type 'Vector' unless it is an instance member of a ref struct.
    // Vector vector; // 타입의 멤버는 불가능

    static void Main(string[] args)
    {
        // 로컬 변수로 스택에 생성되므로 OK!
        Vector v = new Vector { X = 0, Y = 0, Z = 0 };
        v.X = 50;
        Console.WriteLine(v.X);

        PassVector(v);
        PassVectorIn(in v);
    }

    private static void PassVectorIn(in Vector v) // in 매개 변수로 가능
    {
    }

    private static void PassVector(Vector v) // 매개 변수로 가능 (스택에 복사되어 전달되므로.)
    {
    }

    private static Vector GetVector()
    {
        Vector v = new Vector { X = 1, Y = 2, Z = 3 };
        return v; // 로컬 변수의 반환으로도 가능
    }
}

스택에만 생성할 수 있다는 제약으로 인해 당연히 다른 "ref struct"의 필드로는 정의할 수 있습니다.

ref struct Matrix3x3
{
    public Vector v1;
    public Vector v2;
    public Vector v3;
}

또한 메서드도 정의할 수 있지만,

static void Main(string[] args)
{
    Vector v = new Vector { X = 0, Y = 0, Z = 0 };
    v.Output();
}

ref struct Vector
{
    public int X;
    public int Y;
    public int Z;

    public void Output()
    {
        Console.WriteLine($"{X},{Y},{Z}");
    }
}

오직 자신이 정의한 메서드만 사용할 수 있고, 그 외의 (박싱이 발생해 관리 힙으로 올라갈 여지가 있는) 모든 메서드를 사용할 수 없습니다.

Vector v = new Vector { X = 0, Y = 0, Z = 0 };

// 컴파일 오류: CS0029 Cannot implicitly convert type 'ret_struct.Vector' to 'object'
v.GetType();

// 컴파일 오류: CS0029 Cannot implicitly convert type 'reflike.Vector' to 'System.ValueType'
v.ToString();

// 컴파일 오류: CS0029 Cannot implicitly convert type 'reflike.Vector' to 'System.ValueType'
v.Equals(null);

// 컴파일 오류: CS0029 Cannot implicitly convert type 'reflike.Vector' to 'System.ValueType'
v.GetHashCode();

물론, 위의 메서드 중 ToString, Equals, GetHashCode는 ref struct 타입 내에서 재정의(override)하면 사용 가능합니다.

개인적으로 처음 ref struct를 봤을 때 System.TypedReference와 같은 타입을 이제 C#으로도 정의할 수 있게 길을 열어주는 것이 아닌가 생각했었습니다. 하지만, 여전히 ref struct 타입도 관리 포인터를 내부에 정의할 수 없는 제약을 가지고 있습니다.

ref struct IncludeManagedPointer
{
    // 컴파일 에러 - CS0501 'IncludeManagedPointer.Age()' must declare a body because it is not marked abstract, extern, or partial	ref_struct
    public ref int Age;
}

따라서, ref struct는 스택에만 할당할 수 있는 특별한 타입 정의에 불과합니다.




ref struct 구조체 역시 readonly 구조체를 지원합니다.

C# 7.2 - readonly 구조체
; https://www.sysnet.pe.kr/2/0/11524

readonly ref struct Vector
{
    public readonly int X;
    public readonly int Y;
    public readonly int Z;

    public Vector(int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public void Output()
    {
        Console.WriteLine($"{X},{Y},{Z}");
    }
}

그건 그렇다 치고... 그나저나 이런 타입을 도대체 어디다 써먹어야 할까요? ^^ 사실, 일반 개발자들에게는 거의 잊고 지내도 좋을 문법입니다. 아마도 이것은 마이크로소프트가 Span<T>를 위해 도입한 문법일 것이기 때문입니다.

(첨부 파일은 이 글의 예제를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/11/2018]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2018-05-31 11시32분
[spowner] 속도 개선이 주 목적일 텐데, 강제가 아닌 예약어를 사용해야 개선된다는 점은 아쉽네요.
[guest]
2018-06-01 12시09분
ref struct 자체는 속도 개선의 목적은 아니고 Span/TypeReference와 같은 특수 유형의 타입을 점차로 양지로 끌어오는 과정의 하나로 보입니다. 저걸 강제화시키면 그 동안 작성했던 모든 struct 타입들의 사용이 컴파일 오류가 발생하게 됩니다.
정성태

... 151  152  153  154  155  156  157  158  159  160  [161]  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1023정성태4/20/201130088.NET Framework: 210. Windbg 환경에서 확인해 본 .NET 메서드 JIT 컴파일 전과 후 [1]
1022정성태4/19/201125637디버깅 기술: 38. .NET Disassembly 창에서의 F11(Step-into) 키 동작파일 다운로드1
1021정성태4/18/201127970디버깅 기술: 37. .NET 4.0 응용 프로그램의 Main 함수에 BreakPoint 걸기
1020정성태4/18/201128607오류 유형: 117. Failed to find runtime DLL (mscorwks.dll), 0x80004005
1019정성태4/17/201129250디버깅 기술: 36. Visual Studio의 .NET Disassembly 창의 call 호출에 사용되는 주소의 의미는? [1]파일 다운로드1
1018정성태4/16/201132902오류 유형: 116. 윈도우 업데이트 오류 - 0x8020000E
1017정성태4/14/201127686개발 환경 구성: 115. MSBuild - x86/x64, .NET 2/4, debug/release 빌드에 대한 배치 처리파일 다운로드1
1016정성태4/13/201143725개발 환경 구성: 114. Windows Thin PC 설치 [2]
1015정성태4/9/201129099.NET Framework: 209. AutoReset, ManualReset, Monitor.Wait의 차이파일 다운로드1
1014정성태4/7/2011106513오류 유형: 115. ORA-12516: TNS:listener could not find available handler with matching protocol stack [2]
1013정성태4/7/201124294Team Foundation Server: 45. SharePoint 2010 + TFS 2010 환경에서 ProcessGuidance.html 파일 다운로드 문제
1012정성태4/6/201133030.NET Framework: 208. WCF - 접속된 클라이언트의 IP 주소 알아내는 방법 [1]
1011정성태3/31/201135436오류 유형: 114. 인증서 갱신 오류 - The request contains no certificate template information.
1010정성태3/30/201126190개발 환경 구성: 113. 응용 프로그램 디자인 스케치 도구 - SketchFlow [4]
1009정성태3/29/201138563개발 환경 구성: 112. Visual Studio 2010 - .NET Framework 소스 코드 디버깅 [4]
1008정성태3/27/201130913.NET Framework: 207. C# - Right operand가 음수인 Shift 연산 결과 [2]
1007정성태3/16/201131736개발 환경 구성: 111. Excel - XML 파일 연동 [5]파일 다운로드1
1006정성태3/15/201125520.NET Framework: 206. XML/XSD - 외래키처럼 참조 제한 거는 방법파일 다운로드1
1005정성태3/11/201135330개발 환경 구성: 110. 엑셀 매크로 함수 관련 오류 [2]
1004정성태3/3/201124511개발 환경 구성: 109. SharePoint Health Analyzer 디스크 부족 경고 제어
1003정성태3/3/201125517오류 유형: 113. SQL Server - DB Attach 시 Parameter name: nColIndex 오류 발생
1002정성태3/2/201123901Team Foundation Server: 44. TFS 설치 후, Team Portal의 Dashboard를 빠르게 확인하는 방법
1001정성태3/2/201127963Team Foundation Server: 43. TFS 2010 + SharePoint 2010 설치
1000정성태3/1/201132932오류 유형: 112. Remote FX RDP 연결 시 오류 유형 2가지 [5]
999정성태2/28/201146481개발 환경 구성: 108. RemoteFX - Windows 7 가상 머신에서 DirectX 9c 환경을 제공 [5]
998정성태2/27/201120181Team Foundation Server: 42. TFS Application-Tier만 재설치
... 151  152  153  154  155  156  157  158  159  160  [161]  162  163  164  165  ...