다음을 통해 공유


ref readonly 매개 변수

메모

이 문서는 기능 사양입니다. 사양은 기능의 디자인 문서 역할을 합니다. 여기에는 기능 디자인 및 개발 중에 필요한 정보와 함께 제안된 사양 변경 내용이 포함됩니다. 이러한 문서는 제안된 사양 변경이 완료되고 현재 ECMA 사양에 통합될 때까지 게시됩니다.

기능 사양과 완료된 구현 간에 약간의 불일치가 있을 수 있습니다. 이러한 차이는 관련LDM(언어 디자인 모임) 노트에서 캡처됩니다.

사양문서에서 "스펙릿"을 C# 언어 표준으로 채택하는 프로세스에 대해 자세히 알아볼 수 있습니다.

챔피언 이슈: https://github.com/dotnet/csharplang/issues/6010

요약

매개 변수 선언 사이트 한정자 ref readonly 허용하고 다음과 같이 호출 사이트 규칙을 변경합니다.

호출 사이트 주석 ref 매개 변수 ref readonly 매개 변수 in 매개 변수 out 매개 변수
ref 허용 허용됨 경고 오류
in 오류 허용 허용 오류
out 오류 오류 오류 허용
주석 없음 오류 경고 허용 오류

(기존 규칙이 한 가지 변경되었습니다. ref 호출 사이트 주석이 있는 in 매개 변수는 오류 대신 경고를 생성합니다.)

다음과 같이 인수 값 규칙을 변경합니다.

값 종류 ref 매개 변수 ref readonly 매개 변수 in 매개 변수 out 매개 변수
rvalue 오류 경고 허용 오류
lvalue 허용 허용 허용 허용

여기서 lvalue는 변수(즉, 위치가 있는 값, 쓰기 가능/할당 가능할 필요는 없음)를 의미하며 rvalue는 모든 종류의 값을 의미합니다.

동기

C# 7.2 읽기 전용 참조를 전달하는 방법으로in 매개 변수를 도입했습니다. in 매개 변수는 lvalues와 rvalue를 모두 허용하며 호출 사이트에서 주석 없이 사용할 수 있습니다. 그러나 해당 매개 변수에서 참조를 캡처하거나 반환하는 API는 rvalues를 허용하지 않으며 참조가 캡처되고 있음을 호출 사이트에서 일부 표시를 적용하려고 합니다. ref readonly 매개 변수는 rvalues와 함께 사용되거나 호출 사이트에서 주석 없이 사용되는 경우 경고하는 경우에 이상적입니다.

또한 읽기 전용 참조만 필요하지만 사용하는 API도 있습니다.

  • ref 매개 변수는 in이 사용 가능해지기 전에 도입되었기 때문에 in로 변경하는 경우 원본과 이진의 호환성이 손상될 수 있습니다. 예를 들어 QueryInterface같은 경우입니다.
  • rvalue를 전달하는 것이 의미는 없지만, 읽기 전용 참조를 허용하는 in 매개 변수가 있습니다(예: ReadOnlySpan<T>..ctor(in T value)또는).
  • 전달된 참조(예: Unsafe.IsNullRef)를 변경하지 않더라도 rvalue를 허용하지 않도록 ref 매개 변수를 설정하세요.

이러한 API는 사용자를 중단하지 않고 ref readonly 매개 변수로 마이그레이션할 수 있습니다. 이진 호환성에 대한 자세한 내용은 제안된 메타데이터 인코딩참조하세요. 특히 변경 사항

  • refref readonly은 가상 메서드에 대해서만 이진 호환성을 깰 수 있는 변경입니다.
  • refin 가상 메서드에 대한 이진 호환성이 손상되는 변경이지만 원본 호환성이 손상되는 변경은 아닙니다(규칙이 in 매개 변수에 전달된 ref 인수에 대해서만 경고하도록 변경되기 때문).
  • inref readonly는 호환성을 깨는 변경 사항은 아니지만, 호출 사이트 주석 없거나 rvalue일 경우 경고가 발생하지 않습니다.
    • 이 변경 사항은 이전 컴파일러 버전을 사용하는 사용자에게 소스 호환성을 깨는 변화가 될 수 있습니다. 이전 컴파일러 버전은 ref readonly 매개 변수를 ref 매개 변수로 해석하며, 호출 사이트에서 in 또는 주석을 허용하지 않는 문제가 있습니다. LangVersion <= 11를 사용하는 새 컴파일러 버전에서는, 이전 버전과의 일관성을 유지하기 위해, 해당 인수가 ref 한정자와 함께 전달되지 않으면 ref readonly 매개 변수를 지원하지 않는다는 오류가 발생할 것입니다.

반대 방향으로 변경

  • ref readonlyrefref 호출 사이트 주석만 사용되고 인수로 읽기 전용 참조만 사용되는 경우가 아니면 소스를 깨뜨릴 수 있는 잠재적인 변경 사항이며, 가상 메서드에 대해 이진 호환성을 깨뜨릴 수 있는 변경 사항입니다.
  • ref readonlyin 변경은 호환성에 영향을 미치지 않지만, ref 호출 사이트 주석은 경고를 발생시킬 수 있습니다.

위에서 설명한 규칙은 메서드 서명에 적용되지만 서명을 위임하는 데는 적용되지 않습니다. 예를 들어 대리자 서명에서 inref 변경하는 것은 원본 호환성이 손상되는 변경일 수 있습니다(사용자가 ref 매개 변수가 있는 메서드를 해당 대리자 형식에 할당하는 경우 API 변경 후 오류가 발생합니다.)

상세 디자인

일반적으로 ref readonly 매개 변수에 대한 규칙은 이 제안에서 명시적으로 변경된 경우를 제외하고 제안 in 매개 변수에 대해 지정된 규칙과 동일합니다.

매개 변수 선언

문법을 변경할 필요가 없습니다. 매개 변수에 대해 한정자 ref readonly 허용됩니다. 일반 메서드 외에도 ref readonly 인덱서 매개 변수(예: inref와 달리)에 대해 허용되지만 연산자 매개 변수(예: ref는 허용되지만 in달리)는 허용되지 않습니다.

기본 매개 변수 값은 rvalues 전달과 동일하므로 경고가 있는 ref readonly 매개 변수에 대해 허용됩니다. 이렇게 하면 API 작성자가 원본 호환성이 손상되는 변경을 도입하지 않고도 기본값이 있는 in 매개 변수를 ref readonly 매개 변수로 변경할 수 있습니다.

값 종류 검사

비록 ref readonly 매개 변수에 대해 ref 인수 한정자가 허용되더라도, 값 종류 확인과 관련해서는 아무것도 변하지 않습니다, 예를 들어,

  • ref 할당 가능한 값에만 사용할 수 있습니다.
  • 읽기 전용 참조를 전달하려면 대신 in 인수 한정자를 사용해야 합니다.
  • rvalues를 전달하려면 한정자를 사용하지 마세요. 이 경우 ref readonly 매개 변수에 대해 경고가 발생하며, 이는 이 제안의 요약 설명되어 있습니다.

오버로드 해결

오버로드 확인을 사용하면 이 제안 요약을표에 표시된 대로 ref/ref readonly/in/no 호출 사이트 주석 및 매개 변수 한정자를 혼합할 수 있습니다. 즉, 허용되는 모든경고 사례는 오버로드 확인 중에 가능한 후보로 간주됩니다. 특히 in 매개 변수가 있는 메서드가 ref표시된 해당 인수와 호출을 일치시키는 기존 동작이 변경되었습니다. 이 변경 내용은 LangVersion에서 제어됩니다.

그러나 매개 변수가 특정 조건을 충족하는 경우, 호출 사이트 한정자가 없는 인수를 ref readonly 매개 변수에 전달하는 경고는 표시되지 않습니다.

  • 확장 메서드 호출의 수신기
  • 사용자 지정 컬렉션 이니셜라이저 또는 보간된 문자열 처리기의 일부로 암시적으로 사용됩니다.

인수 한정자가 없는 경우 ref readonly 오버로드보다 값별 오버로드가 선호됩니다(in 매개 변수의 동작이 동일).

메서드 변환

마찬가지로 익명 함수 [§10.7] 및 메서드 그룹 [§10.8] 변환을 위해 이러한 한정자는 호환되는 것으로 간주됩니다(하지만 다른 한정자 간에 허용되는 변환은 경고가 발생함).

  • 대상 메서드의 ref readonly 매개 변수는 대리자의 in 또는 ref 매개 변수와 일치하도록 허용됩니다.
  • 대상 메서드의 in 매개변수는 ref readonly 매개변수와 일치할 수 있고, 또는 LangVersion에 따라 제어되는 경우 ref 대리자의 매개 변수가 될 수 있습니다.
  • 참고: 대상 메서드의 ref 매개 변수는 대리자의 in 또는 ref readonly 매개 변수와 일치하도록 허용되지 않습니다.

예를 들어:

DIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`
DRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`
DRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`
dRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`
dIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`
dRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`
delegate void DIn(in int p);
delegate void DRef(ref int p);
delegate void DRR(ref readonly int p);

함수 포인터 변환동작이 변경되지 않았음을 유의하십시오. 참고로 참조 종류 한정자 간에 불일치가 있는 경우 암시적 함수 포인터 변환이 허용되지 않으며 명시적 캐스트는 경고 없이 항상 허용됩니다.

서명 일치

단일 형식으로 선언된 멤버는 ref/out/in/ref readonly만 서명에서 다를 수 없습니다. 서명 일치(예: 숨기기 또는 재정의)의 다른 목적을 위해 ref readonlyin 한정자와 교환할 수 있지만 선언 사이트에서 경고가 발생합니다[§7.6]. 이는 partial 선언을 구현과 일치시키는 경우와 인터셉터 서명을 가로챈 서명과 일치시키는 경우에는 적용되지 않습니다. 서명이 이진적으로 호환되지 않기 때문에 ref/inref readonly/ref 수정자 쌍은 변경될 수 없으며, 교환될 수 없습니다. 일관성의 경우 다른 서명 일치 목적(예: 숨기기)에도 마찬가지입니다.

메타데이터 인코딩

미리 알림으로,

  • ref 매개 변수는 IL에서 일반 바이레프 형식(T&)으로 내보내집니다.
  • in 매개 변수는 ref 같고 System.Runtime.CompilerServices.IsReadOnlyAttribute주석이 추가됩니다. C# 7.3 이상에서는 [in]와 함께, 그리고 가상인 경우에는 modreq(System.Runtime.InteropServices.InAttribute)로 내보내집니다.

ref readonly 매개 변수는 [in] T&으로 내보내지며, 다음 속성으로 주석이 추가됩니다.

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public sealed class RequiresLocationAttribute : Attribute
    {
    }
}

또한 가상인 경우, in 매개 변수와의 바이너리 호환성을 보장하기 위해 modreq(System.Runtime.InteropServices.InAttribute)가 내보내질 것입니다. in 매개 변수와 달리 메타데이터 크기 증가를 방지하고 이전 컴파일러 버전이 ref readonly 매개 변수를 ref 매개 변수로 해석하도록 하기 위해 ref readonly 매개 변수에 대한 [IsReadOnly] 내보내지 않습니다(따라서 refref readonly 다른 컴파일러 버전 간에도 소스 호환성이 손상되는 변경이 되지 않음).

RequiresLocationAttribute는 네임스페이스로 정규화된 이름과 일치하며, 컴파일에 포함되지 않은 경우 컴파일러에서 합성됩니다.

ParamArrayAttribute마찬가지로 매개 변수에 적용되는 경우 원본에서 특성을 지정하면 오류가 발생합니다.

함수 포인터

함수 포인터에서 in 매개 변수는 modreq(System.Runtime.InteropServices.InAttribute) 함께 내보내집니다(함수 포인터 제안참조). ref readonly 매개 변수는 modreq없이 내보내지며 대신 modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)와 함께 내보내집니다. 이전 컴파일러 버전에서는 modopt 무시하고 ref readonly 매개 변수를 ref 매개 변수로 해석하고(위에서 설명한 대로 ref readonly 매개 변수를 사용하는 일반 메서드의 이전 컴파일러 동작과 일치) modopt 인식하는 새 컴파일러 버전에서는 ref readonly 매개 변수를 인식하여 변환 및 호출중에 경고를 내보낸다. 이전 컴파일러 버전과의 일관성을 위해 LangVersion <= 11 있는 새 컴파일러 버전은 해당 인수가 ref 한정자와 함께 전달되지 않는 한 ref readonly 매개 변수가 지원되지 않는 오류를 보고합니다.

함수 포인터 서명이 공용 API의 일부인 경우, 함수 포인터 서명의 한정자를 변경하면 이진 호환성 중단이 발생할 수 있습니다. 따라서 ref 또는 inref readonly로 변경하면 이진 호환성 중단이 발생하게 됩니다. 그러나 소스 중단은 일반 메서드와 일치하는 inref readonly 변경할 때(in 호출 사이트 한정자를 사용하여 포인터를 호출하는 경우) LangVersion <= 11 있는 호출자에 대해서만 발생합니다.

주요 변경 내용

오버로드 확인의 ref/in 불일치 완화는 다음 예제에 설명된 동작 호환성이 손상되는 변경을 도입합니다.

class C
{
    string M(in int i) => "C";
    static void Main()
    {
        int i = 5;
        System.Console.Write(new C().M(ref i));
    }
}
static class E
{
    public static string M(this C c, ref int i) => "E";
}

C# 11에서는 호출이 E.M으로 바인딩되므로 "E"이 출력됩니다. C# 12에서는 C.M 바인딩할 수 있으며(경고 포함) 해당 후보가 있으므로 확장 범위가 검색되지 않으므로 "C" 인쇄됩니다.

동일한 이유로 인해 원본 호환성이 손상되는 변경도 있습니다. 아래 예제에서는 C# 11에서 "1" 인쇄하지만 C# 12의 모호성 오류로 컴파일하지 못합니다.

var i = 5;
System.Console.Write(C.M(null, ref i));

interface I1 { }
interface I2 { }
static class C
{
    public static string M(I1 o, ref int x) => "1";
    public static string M(I2 o, in int x) => "2";
}

위의 예제에서는 메서드 호출에 대한 중단을 보여 주지만 오버로드 확인 변경으로 인해 발생하므로 메서드 변환에 대해 유사하게 트리거될 수 있습니다.

대안

매개 변수 선언

API 작성자는 사용자 지정 특성이 있는 lvalue만 허용하도록 설계된 in 매개 변수에 주석을 달고 잘못된 사용량에 플래그를 지정하는 분석기를 제공할 수 있습니다. 이렇게 하면 API 작성자가 ref 매개 변수를 사용하여 rvalues를 허용하지 않도록 선택한 기존 API의 서명을 변경할 수 없습니다. 이러한 API의 호출자는 ref readonly 변수에만 액세스할 수 있는 경우 ref 가져오기 위해 추가 작업을 수행해야 합니다. 이러한 API를 ref[RequiresLocation] in 변경하는 것은 원본 호환성이 손상되는 변경입니다(가상 메서드의 경우 이진 호환성이 손상되는 변경).

컴파일러는 한정자 ref readonly허용하는 대신 매개 변수에 특수 특성(예: [RequiresLocation])이 적용될 때를 인식할 수 있습니다. 이는 LDM 2022-04-25설명되었으며, 분석기가 아닌 언어 기능이라고 결정하므로 다음과 같이 표시되어야 합니다.

값 종류 확인

C++의 암시적 바이리프 매개 변수와 마찬가지로 ref readonly 매개 변수에 한정자 없이 lvalues를 전달하는 것은 경고 없이 허용될 수 있습니다. 이는 LDM 2022-05-11설명되었으며, ref readonly 매개 변수의 주된 동기는 이러한 매개 변수에서 참조를 캡처하거나 반환하는 API이므로 어떤 종류의 마커가 좋은 것입니다.

rvalue를 ref readonly에 전달하는 것은 경고가 아닌 오류가 될 수 있습니다. 처음에는 LDM 2022-04-25의 제안이 수락되었지만, 이후 이메일 논의를 통해 기존 API를 변경할 때 사용자에게 영향을 주지 않기 위해 이 결정을 완화하였습니다.

in ref readonly 매개 변수에 대한 "자연" 호출 사이트 한정자일 수 있으며 ref 사용하면 경고가 발생할 수 있습니다. 이렇게 하면 일관된 코드 스타일이 보장되고 호출 사이트에서 참조가 읽기 전용임을 분명히 할 수 있습니다(ref달리). 처음에는 LDM 2022-04-25허용되었습니다. 그러나 경고는 API 작성자가 ref에서 ref readonly로 이동하는 데 있어 마찰 지점이 될 수 있습니다. inref readonly과 편의 기능을 더해 다시 정의되었으며, 이로 인해 2022-05-11 LDM에서은 거부되었습니다.

LDM 검토 보류 중

C# 12에서는 다음 옵션 중 어느 것도 구현되지 않았습니다. 잠재적 제안이 존재한다.

매개 변수 선언

한정자(ref readonly대신readonly ref)의 역순으로 사용할 수 있습니다. 이는 readonly ref 반환 및 필드 동작 방식과 일치하지 않으며(역순이 허용되지 않거나 각각 다른 것을 의미함) 나중에 구현될 경우 읽기 전용 매개 변수와 충돌할 수 있습니다.

기본 매개 변수 값은 ref readonly 매개 변수에 대한 오류일 수 있습니다.

값 종류 확인

rvalues를 ref readonly 매개 변수에 전달하거나 호출 사이트 주석 및 매개 변수 한정자가 일치하지 않을 때 경고 대신 오류를 내보냅니다. 마찬가지로 특성 대신 특수 modreq 사용하여 ref readonly 매개 변수가 이진 수준의 in 매개 변수와 구별되도록 할 수 있습니다. 이렇게 하면 더 강력한 보장이 제공되므로 새 API에 적합하지만 호환성이 손상되는 변경을 도입할 수 없는 기존 런타임 API의 채택을 방지할 수 있습니다.

값 종류 검사는 ref 통해 읽기 전용 참조를 in/ref readonly 매개 변수에 전달할 수 있도록 완화할 수 있습니다. 이는 ref 할당 및 ref 반환이 오늘날 작동하는 방식과 유사할 것입니다. 이러한 방식은 원본 식의 ref 한정자를 통해 참조를 읽기 전용으로 전달할 수 있도록 합니다. 그러나 ref은 대개 대상이 ref readonly로 선언되는 장소에 가깝기 때문에, 인수 및 매개 변수 한정자가 보통 멀리 떨어져 있는 호출과는 달리, 참조를 읽기 전용으로 전달하고 있다는 것이 명확합니다. 또한 ref 한정자는 인수와 달리 만 허용하므로, in도 허용하는 인수의 경우 inref가 서로 교환 가능하게 됩니다. 사용자가 코드를 일관되게 유지하려는 경우, 아마도 in는 실질적으로 사용되지 않게 되고, ref 할당 및 ref 반환에 허용되는 유일한 한정자이므로 모든 곳에서 ref를 사용할 것입니다.

오버로드 확인

오버로드 해결, 재정의 및 변환은 ref readonlyin 한정자의 교환성을 허용하지 않을 수 있습니다.

기존 in 매개 변수에 대한 오버로드 해석 변경은 무조건적으로(LangVersion을 고려하지 않음)할 수 있지만, 이는 호환성을 깨뜨리는 변경이 될 수 있습니다.

ref readonly 수신기를 사용하여 확장 메서드를 호출하면 호출 사이트 한정자가 없는 확장이 아닌 호출에서와 마찬가지로 "인수 1을 ref 또는 in 키워드로 전달해야 합니다."라는 경고가 발생할 수 있습니다(사용자는 확장 메서드 호출을 정적 메서드 호출로 전환하여 이러한 경고를 수정할 수 있음). 사용자가 이를 해결할 수 없는 경우에도 사용자 지정 컬렉션 이니셜라이저 또는 보간된 문자열 처리기를 ref readonly 매개 변수와 함께 사용할 때 동일한 경고가 발생할 수 있습니다.

호출 사이트 한정자가 없거나 모호성 오류가 있을 경우 값별 오버로드보다 ref readonly 오버로드를 선호할 수 있습니다.

메소드 변환

대상 메서드의 ref 매개 변수가 대리자의 inref readonly 매개 변수와 일치하도록 허용할 수 있습니다. 이렇게 하면 API 작성자가 사용자를 중단하지 않고 대리자 서명에서 refin로 변경할 수 있습니다(일반적인 메서드 서명에서 허용되는 것과 일관되게). 그러나 다음과 같이 경고와 함께 readonly 보증을 위반하게 됩니다.

class Program
{
    static readonly int f = 123;
    static void Main()
    {
        var d = (in int x) => { };
        d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`
        d(f); // changes value of `f` even though it is `readonly`!
        System.Console.WriteLine(f); // prints 42
    }
}

함수 포인터 변환은 ref readonly/ref/in 불일치에 대해 경고할 수 있지만 LangVersion에서 제어하려면 현재 형식 변환이 컴파일에 액세스할 필요가 없으므로 상당한 구현 투자가 필요합니다. 또한 현재 불일치가 오류임에도 불구하고 사용자가 원하는 경우 불일치를 허용하도록 캐스트를 쉽게 추가할 수 있습니다.

메타데이터 인코딩

InOut 특성과 마찬가지로 원본에서 RequiresLocationAttribute 지정할 수 있습니다. 또는 매개 변수가 아닌 다른 컨텍스트에서 적용할 때 IsReadOnly 특성과 유사하게 오류가 발생할 가능성이 있습니다. 추가적인 설계 공간을 보존하기 위해서입니다.

함수 포인터 ref readonly 매개변수는 서로 다른 modopt/modreq 조합으로 나타날 수 있습니다(이 표에서 "소스 중단"은 LangVersion <= 11호출자에게 의미합니다).

한정자 컴파일에서 인식할 수 있습니다. 이전 컴파일러는 그것들을 간주합니다. refref readonly inref readonly
modreq(In) modopt(RequiresLocation) in 이진수, 소스 코드 중단 이진 나누기
modreq(In) 아니요 in 이진, 소스 중단 그래
modreq(RequiresLocation) 지원 되지 않는 이진, 소스 중단 이진, 소스 중단
modopt(RequiresLocation) ref 이진 나누기 이진, 소스 분리

ref readonly 매개 변수에 대해 [RequiresLocation][IsReadOnly] 특성을 모두 내보낼 수 있다. 그런 다음 inref readonly 이전 컴파일러 버전에서도 호환성이 손상되는 변경은 아니지만 refref readonly 이전 컴파일러 버전(ref readonlyin해석하고 ref 한정자를 허용하지 않음)과 LangVersion <= 11 사용하는 새 컴파일러 버전(일관성을 위해)에 대한 소스 호환성이 손상되는 변경이 됩니다.

LangVersion <= 11 동작을 이전 컴파일러 버전의 동작과 다르게 만들 수 있습니다. 예를 들어 호출 사이트에서 ref 한정자를 사용하는 경우에도 ref readonly 매개 변수가 호출될 때마다 오류가 발생하거나 오류 없이 항상 허용될 수 있습니다.

중요한 변경 사항

이 제안은 적중이 드물고, LangVersion에 의해 제어되며, 사용자가 확장 메서드를 명시적으로 호출하여 해결할 수 있기 때문에 동작 호환성이 손상되는 변경을 수락하는 것을 제안합니다. 대신 다음을 통해 완화할 수 있습니다.

  • ref / in 불일치를 허용하지 않습니다(in 아직 사용할 수 없기 때문에 ref 사용한 이전 API의 in 마이그레이션만 방지)
  • 제안된 참조 종류 불일치가 있을 때, 아래에 명시된 '더 나은 기준'에 따라 더 나은 일치를 계속 찾을 수 있도록 오버로드 결정 규칙을 수정합니다.
    • 또는 다른 항목이 아닌 refin 불일치에 대해서만 계속 진행합니다(값 기준으로ref readonly vs. ref/in).
개선 규칙

다음 예제에서는 현재 세 번의 M호출에 대해 세 가지 모호성 오류가 발생합니다. 모호성을 해결하기 위해 새로운 개선 규칙을 추가할 수 있습니다. 이렇게 하면 앞에서 설명한 원본 호환성이 손상되는 변경도 해결됩니다. 한 가지 방법은 예제가 221을 출력하도록 하는 것입니다. 이때 ref readonly 매개변수가 in 인수와 일치해야 하며, 이는 한정자 없이 호출하면 경고가 발생하는 상황인 반면, in 매개변수의 경우에는 허용됩니다.

interface I1 { }
interface I2 { }
class C
{
    static string M(I1 o, in int i) => "1";
    static string M(I2 o, ref readonly int i) => "2";
    static void Main()
    {
        int i = 5;
        System.Console.Write(M(null, ref i));
        System.Console.Write(M(null, in i));
        System.Console.Write(M(null, i));
    }
}

새로운 개선 규칙에 의해, 더 나은 인수 한정자로 변경해 전달할 수 있는 인수를 가지고 있는 매개 변수가 더 나빠진 것으로 표시될 수 있습니다. 즉, 사용자는 항상 해당 인수 한정자를 변경하여 더 나쁜 매개 변수를 더 나은 매개 변수로 바꿀 수 있어야 합니다. 예를 들어 인수가 in전달되면 사용자가 인수를 값별로 전달하여 in 매개 변수를 선택할 수 있으므로 in 매개 변수보다 ref readonly 매개 변수를 사용하는 것이 좋습니다. 이 규칙은 현재 적용되는 값별/in 기본 설정 규칙의 확장일 뿐입니다(마지막 오버로드 확인 규칙이며 매개 변수가 더 낫고 다른 오버로드의 해당 매개 변수보다 더 나쁜 항목이 없는 경우 전체 오버로드가 더 좋습니다).

논쟁 더 나은 매개 변수 더 나쁜 매개변수
ref/in ref readonly in
ref ref ref readonly/in
값별 값별/in ref readonly
in in ref

메서드 변환도 마찬가지로 처리해야 합니다. 다음 예제에서는 현재 두 대리자 할당에 대해 두 가지 모호성 오류가 발생합니다. 새로운 우선순위 규칙은 해당 대상 대리자 매개변수의 참조 유형 한정자와 일치하는 메서드 매개변수를, 일치하지 않는 매개변수보다 선호할 수 있습니다. 따라서 다음 예제에서는 12인쇄합니다.

class C
{
    void M(I1 o, ref readonly int x) => System.Console.Write("1");
    void M(I2 o, ref int x) => System.Console.Write("2");
    void Run()
    {
        D1 m1 = this.M;
        D2 m2 = this.M; // currently ambiguous

        var i = 5;
        m1(null, in i);
        m2(null, ref i);
    }
    static void Main() => new C().Run();
}
interface I1 { }
interface I2 { }
class X : I1, I2 { }
delegate void D1(X s, ref readonly int x);
delegate void D2(X s, ref int x);

디자인 회의