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 타입들의 사용이 컴파일 오류가 발생하게 됩니다.
정성태

... 181  182  183  184  185  186  187  188  [189]  190  191  192  193  194  195  ...
NoWriterDateCnt.TitleFile(s)
228정성태4/13/200615880Team Foundation Server: 3. MSBUILD : warning : Visual Studio Team System for Software Testers or Visual Studio Team System for Software Developers is required to run tests as part of a Team Build.
227정성태4/13/200617448Team Foundation Server: 2. TFS 빌드 오류 유형 - MSBUILD: warning : Specified cast is not valid
226정성태4/13/200615434Team Foundation Server: 1. TFS 오류 유형 - TF50608: Unable to retrieve information for security object
225정성태10/17/200614995.NET Framework: 67. VS.NET 2005 도구 상자에 있는 Workflow Activity 항목의 아이콘 변경
223정성태4/13/200626261.NET Framework: 66. Microsoft .NET Framework 2.0 Configuration 수동 설치파일 다운로드1
224정성태4/13/200619809    답변글 .NET Framework: 66.1. "Microsoft .NET Framework 2.0 Configuration" MSI 설치 파일 버전파일 다운로드1
222정성태4/13/200618781.NET Framework: 65. VS.NET 2005: 파일 기반 웹 프로젝트의 "Virtual Path" 제거
220정성태4/13/200616552.NET Framework: 64. ClickOnce - 배포 시 오류 : "Error: An unexpected error occurred -- The parameter is incorrect."
219정성태4/13/200631381.NET Framework: 63. ClickOnce - 최초 실행 시 보안 경고창 없애는 방법 [1]
216정성태4/13/200618427스크립트: 8. 3월 1일 ActiveX Patch 적용 후, JS 로 수정한 임베딩 컨트롤이 여전히 비활성화 되는 문제 [2]
215정성태4/13/200619754.NET Framework: 62. ASP.NET 웹 컨트롤 렌더링 가로채기
214정성태4/13/200619090.NET Framework: 61. DateTime - DateTime = 사이의 "Month" 수 계산 [2]
213정성태4/13/200621374.NET Framework: 60. localhost 이외의 컴퓨터에서 asmx 테스트 페이지 호출 [1]
218정성태4/13/200619723    답변글 .NET Framework: 60.1. asmx 테스트 페이지를 보여주고 싶지 않을 때
211정성태4/13/200617617VS.NET IDE: 38. VS.NET 2005 - "Export Template" 메뉴
210정성태4/13/200617109.NET Framework: 59. EXE 참조 가능 - VS.NET 2005 [2]
209정성태4/13/200616533스크립트: 7. 4월 12일 ActiveX 패치 문제를 해결할 수 있는 가장 간단한 방법 [6]파일 다운로드1
208정성태10/21/200616325Windows: 1. 성태도 ^^ Vista 설치 해봤습니다.
212정성태10/20/200615883    답변글 Windows: 1.1. Vista 에서 WinFX 런타임 구동
207정성태4/13/200624850VC++: 23. VC++ RGS 파일에 사용자 정의 파라미터 추가
205정성태4/13/200621913VS.NET IDE: 37. devenv.exe를 이용한 Command Line 컴파일 [1]
204정성태5/8/200617128웹: 2. Server Unavailable - Server Application Unavailable
203정성태4/13/200615963웹: 1. IIS 설정 옵션: Verify(Check) that file exists
202정성태4/13/200615654VS.NET IDE: 36. Automatically synchronize with an Internet time server
201정성태4/13/200618733기타: 12. XMLHTTP Failure and SUS Admin
200정성태4/13/200618077.NET Framework: 58. 웹 서비스 메서드 호출 오류 유형 - text/html; charset=xxx, but expected 'text/xml'
... 181  182  183  184  185  186  187  188  [189]  190  191  192  193  194  195  ...