Visual Studio 2019 Preview 4/RC - C# 8.0 Missing compiler required member 'System.Range..ctor'
현재 2019 (Preview 3은 괜찮고) Preview 4와 RC 버전에서 Range를 사용하면 다음과 같은 컴파일 오류가 발생합니다.
Program.cs(21,33,21,38): error CS0656: Missing compiler required member 'System.Range..ctor'
이 문제가 roslyn 이슈에도 올라와 있는데요.
CS0656: Missing compiler required member (.Net Core 3.0 Preview 2, Visual Studio 2019 Preview) #2364
; https://github.com/dotnet/core/issues/2364
문제의 원인은 Preview4/RC에 들어가 있는 C# 8.0 컴파일러가 System.Range의 생성자를 접근하도록 바뀌었는데 역시 Preview 버전의 .NET Core 3.0에 포함된 System.Runtime.System.Range 타입에는 없기 때문입니다. (아마도 C# 8.0 컴파일러 개발자들은 이미 업데이트된 .NET Core 3.0 preview 버전을 사용하고 있어서 에러가 없었을 것입니다.)
이 문제는 다음번 .NET Core 3.0 preview가 나오면 자연스럽게 해결되겠지만 그전까지는 지난 글의 방법에 따라,
C# 8.0의 Index/Range 연산자를 .NET Framework에서 사용하는 방법 및 비동기 스트림의 컴파일 방법
; https://www.sysnet.pe.kr/2/0/11835
다음과 같이 변경된 ranges.cs 파일을 추가해 빌드하는 식으로 우회할 수 있습니다. (2개의 변경 사항이 있습니다.)
namespace System
{
public readonly struct Index
{
private readonly int _value;
public int Value => _value < 0 ? ~_value : _value;
public bool FromEnd => _value < 0;
public bool IsFromEnd => _value < 0;
public Index(int value, bool fromEnd)
{
if (value < 0) throw new ArgumentException("Index must not be negative.", nameof(value));
_value = fromEnd ? ~value : value;
}
public static implicit operator Index(int value)
=> new Index(value, fromEnd: false);
public int GetOffset(int length)
{
int num = this._value;
if (this.IsFromEnd)
{
num = (int) (num + (length + 1));
}
return num;
}
}
public readonly struct Range
{
public Index Start { get; }
public Index End { get; }
public Range(Index start, Index end)
{
this.Start = start;
this.End = end;
}
public static Range Create(Index start, Index end) => new Range(start, end);
public static Range FromStart(Index start) => new Range(start, new Index(0, fromEnd: true));
public static Range ToEnd(Index end) => new Range(new Index(0, fromEnd: false), end);
public static Range All() => new Range(new Index(0, fromEnd: false), new Index(0, fromEnd: true));
}
static class Extensions
{
public static int get_IndexerExtension(this int[] array, Index index) =>
index.FromEnd ? array[array.Length - index.Value] : array[index.Value];
public static int get_IndexerExtension(this Span<int> span, Index index) =>
index.FromEnd ? span[span.Length - index.Value] : span[index.Value];
public static char get_IndexerExtension(this string s, Index index) =>
index.FromEnd ? s[s.Length - index.Value] : s[index.Value];
public static Span<int> get_IndexerExtension(this int[] array, Range range) =>
array.Slice(range);
public static Span<int> get_IndexerExtension(this Span<int> span, Range range) =>
span.Slice(range);
public static string get_IndexerExtension(this string s, Range range) =>
s.Substring(range);
public static Span<T> Slice<T>(this T[] array, Range range)
=> array.AsSpan().Slice(range);
public static Span<T> Slice<T>(this Span<T> span, Range range)
{
var (start, length) = GetStartAndLength(range, span.Length);
return span.Slice(start, length);
}
public static string Substring(this string s, Range range)
{
var (start, length) = GetStartAndLength(range, s.Length);
return s.Substring(start, length);
}
private static (int start, int length) GetStartAndLength(Range range, int entityLength)
{
var start = range.Start.FromEnd ? entityLength - range.Start.Value : range.Start.Value;
var end = range.End.FromEnd ? entityLength - range.End.Value : range.End.Value;
var length = end - start;
return (start, length);
}
}
}
참고로 .NET Core 3.0 프로젝트에서는 위와 같은 소스 코드를 함께 포함하면 타입 충돌 경고가 뜨는데 일단은 무시하면 됩니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]