確認環境
- .NET 8
LangVersion
に latest
を指定すると最新のC#バージョンになる。デフォルトは TargetFramework
で決まる。
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
以下は、C# 7.3 より後に実装された機能が .NET Framework 4.7.2 で使用できるかの調査結果。
凡例
凡例 | 意味 |
---|---|
✅ | 対応 |
⚠️ | 部分的に対応 |
⛔ | 未対応 |
❔ | 影響なし |
⛔ 使用できない機能一覧
- 既定のインターフェイスメソッド
- ジェネリック数値演算
-
ref
フィールド - 警告ウェーブ7
- インライン配列
C# 8
✅ Readonly member: 読み取り専用メンバー
struct Foo
{
private int _value;
public readonly int GetValue() => _value;
}
⛔ Default interface methods: 既定のインターフェイスメソッド
ランタイムレベルの対応が必要なので使用不可。
interface IFoo
{
int GetValue() => 1;
}
error CS8701: ターゲット ランタイムは、既定のインターフェイスの実装をサポートしていません。
✅ Pattern matching enhancements: パターンマッチングの拡張
✅ switch式
var x = 1;
var r = x switch
{
0 => '0',
1 => '1',
_ => '?',
};
✅ プロパティーパターン
var x = DateTime.Now;
var r = x is { Year: 2023, Month: 12 };
✅ 位置指定パターン
var x = (1, 2);
var r = x switch
{
(0, 0) => 0,
(1, 2) => 1,
_ => -1,
};
✅ Using declarations: using 宣言
using var stream = new MemoryStream();
✅ Static local functions: 静的ローカル関数
static int GetValue() => 1;
GetValue();
✅ Disposable ref structs: 破棄可能な ref 構造体
using var foo = new Foo();
ref struct Foo
{
public void Dispose() { }
}
⚠️ Nullable reference types: Null 許容参照型
BCLの支援はないが、ユーザーコード内であれば問題なく使用できる。
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
string? x = null;
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
public sealed class AllowNullAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
public sealed class DisallowNullAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
public sealed class MaybeNullAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
public sealed class NotNullAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public sealed class MaybeNullWhenAttribute : Attribute
{
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
public bool ReturnValue { get; }
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public sealed class NotNullWhenAttribute : Attribute
{
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
public bool ReturnValue { get; }
}
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
public sealed class NotNullIfNotNullAttribute : Attribute
{
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
public string ParameterName { get; }
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class DoesNotReturnAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public sealed class DoesNotReturnIfAttribute : Attribute
{
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
public bool ParameterValue { get; }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public sealed class MemberNotNullAttribute : Attribute
{
public MemberNotNullAttribute(string member) => Members = new[] { member };
public MemberNotNullAttribute(params string[] members) => Members = members;
public string[] Members { get; }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public sealed class MemberNotNullWhenAttribute : Attribute
{
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new[] { member };
}
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
public bool ReturnValue { get; }
public string[] Members { get; }
}
}
✅ Asynchronous streams: 非同期ストリーム
await foreach (var value in GetValuesAsync())
{
Console.WriteLine(value);
}
async IAsyncEnumerable<int> GetValuesAsync()
{
for (var i = 0; i < 10; i++)
{
await Task.Delay(1000);
yield return i;
}
}
dotnet add package Microsoft.Bcl.AsyncInterfaces
⚠️ Indices and ranges: インデックスと範囲
公式のパッケージが存在しない。
var arr = new byte[10];
var sub = arr[1..2];
非公式のパッケージ。
dotnet add package IndexRange
または自分で定義。
namespace System
{
public readonly struct Index : IEquatable<Index>
{
private readonly int _value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Index(int value, bool fromEnd = false)
{
if (value < 0)
{
ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}
if (fromEnd)
_value = ~value;
else
_value = value;
}
private Index(int value)
{
_value = value;
}
public static Index Start => new Index(0);
public static Index End => new Index(~0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromStart(int value)
{
if (value < 0)
{
ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}
return new Index(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromEnd(int value)
{
if (value < 0)
{
ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}
return new Index(~value);
}
public int Value
{
get
{
if (_value < 0)
return ~_value;
else
return _value;
}
}
public bool IsFromEnd => _value < 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetOffset(int length)
{
int offset = _value;
if (IsFromEnd)
{
offset += length + 1;
}
return offset;
}
public override bool Equals([NotNullWhen(true)] object? value) => value is Index && _value == ((Index)value)._value;
public bool Equals(Index other) => _value == other._value;
public override int GetHashCode() => _value;
public static implicit operator Index(int value) => FromStart(value);
public override string ToString()
{
if (IsFromEnd)
return ToStringFromEnd();
return ((uint)Value).ToString();
}
private static void ThrowValueArgumentOutOfRange_NeedNonNegNumException()
{
throw new ArgumentOutOfRangeException("value", "value must be non-negative");
}
private string ToStringFromEnd()
{
return '^' + Value.ToString();
}
}
public readonly struct Range : IEquatable<Range>
{
public Index Start { get; }
public Index End { get; }
public Range(Index start, Index end)
{
Start = start;
End = end;
}
public override bool Equals([NotNullWhen(true)] object? value) =>
value is Range r &&
r.Start.Equals(Start) &&
r.End.Equals(End);
public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End);
public override int GetHashCode()
{
return Start.GetHashCode() << 16 | End.GetHashCode();
}
public override string ToString()
{
return Start.ToString() + ".." + End.ToString();
}
public static Range StartAt(Index start) => new Range(start, Index.End);
public static Range EndAt(Index end) => new Range(Index.Start, end);
public static Range All => new Range(Index.Start, Index.End);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (int Offset, int Length) GetOffsetAndLength(int length)
{
int start = Start.GetOffset(length);
int end = End.GetOffset(length);
if ((uint)end > (uint)length || (uint)start > (uint)end)
{
ThrowArgumentOutOfRangeException();
}
return (start, end - start);
}
private static void ThrowArgumentOutOfRangeException()
{
throw new ArgumentOutOfRangeException("length");
}
}
}
RuntimeHelpers.GetSubArray
の定義。
namespace System.Runtime.CompilerServices
{
public static partial class RuntimeHelpers
{
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
(int offset, int length) = range.GetOffsetAndLength(array.Length);
T[] dest;
if (typeof(T[]) == array.GetType())
{
if (length == 0)
{
return Array.Empty<T>();
}
dest = new T[length];
}
else
{
dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length);
}
Array.Copy(array, offset, dest, 0, length);
return dest;
}
}
}
✅ Null-coalescing assignment: null 合体割り当て
string? v = null;
v ??= "";
✅ Unmanaged constructed types: 構築されたアンマネージド型
void Foo<T>() where T : unmanaged
{
}
✅ Stackalloc in nested expressions: 入れ子になった式の stackalloc
式の中で stackalloc
が可能。ただしポインター T*
ではなく Span<T>
となる。
Foo(stackalloc int[1]);
void Foo(Span<int> p) { }
dotnet add package System.Memory
✅ Enhancement of interpolated verbatim strings: verbatim 補間文字列の拡張
var a = $@"";
var b = @$"";
C# 9
✅ Records: レコード
record C(int Value, string Name);
with
式で変更。
var c1 = new C(1, "v1");
var c2 = c1 with { Value = 2 };
✅ Init only setters: init 専用セッター
class C
{
public int Value { get; init; }
}
namespace System.Runtime.CompilerServices
{
public static class IsExternalInit { }
}
✅ Top-level statements: 最上位レベルのステートメント
{ }
✅ Pattern matching enhancements: パターンマッチングの拡張
relational patterns: リレーショナルパターン >
<
<=
>=
var x = 10;
var r = x switch
{
< 1 => "low",
> 5 => "hi",
_ => "ok",
};
logical patterns: 論理パターン and
or
not
var x = 10;
var r = x switch
{
< 1 or > 5 => "outer",
> 2 and < 4 => "center",
_ => "inner",
};
int? n = null;
if (n is not null) { }
✅ Performance and interop: パフォーマンスと相互運用
✅ Native sized integers: ネイティブサイズの整数
nint x = 1;
⚠️ Function pointers: 関数ポインター
unsafe
{
delegate* managed<int> f1;
delegate* unmanaged[Cdecl]<int> f2;
}
⛔
delegate* unmanaged<int>
のように呼び出し規約を省略することはできない。
✅ Suppress emitting localsinit flag: localsinit フラグの出力を抑制
[SkipLocalsInit]
unsafe void Foo()
{
var v = stackalloc byte[100];
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Module
| AttributeTargets.Class
| AttributeTargets.Struct
| AttributeTargets.Interface
| AttributeTargets.Constructor
| AttributeTargets.Method
| AttributeTargets.Property
| AttributeTargets.Event, Inherited = false)]
public sealed class SkipLocalsInitAttribute : Attribute { }
}
✅ Module initializers: モジュール初期化子
static class C
{
[ModuleInitializer]
internal static void M()
{
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ModuleInitializerAttribute : Attribute { }
}
✅ New features for partial methods: 部分メソッドの新機能
戻り値が void
ではない部分メソッドをサポート。
partial class C
{
public partial int GetValue();
}
partial class C
{
public partial int GetValue() => 1;
}
✅ Fit and finish features: 適合性と完成度の機能
✅ Target-typed new expressions: ターゲットにより型指定された new 式
List<int> list = new();
✅ static anonymous functions: 静的匿名関数
Func<int> f = static () => 1;
✅ Target-typed conditional expressions: ターゲットにより型指定された条件式
A a = true ? new A1() : new A2();
class A { }
class A1 : A { }
class A2 : A { }
❔ Covariant return types: 共変の戻り値の型
この機能は実装されていない。
✅ Extension GetEnumerator support for foreach loops: foreach
で GetEnumerator
拡張メソッドに対応
foreach (var v in new C())
{
Console.WriteLine(v);
}
class C
{
public int V1 = 1;
public int V2 = 2;
}
static class CExtensions
{
public static CEnumerator GetEnumerator(this C c) => new(c);
public struct CEnumerator : IEnumerator<int>
{
private readonly C c;
private int index;
public CEnumerator(C c)
{
this.c = c;
this.index = 0;
}
public int Current => index == 1 ? this.c.V1 : index == 2 ? this.c.V2 : -1;
object IEnumerator.Current => this.Current;
public void Dispose() { }
public bool MoveNext()
{
if (index is 0 or 1)
{
index++;
return true;
}
return false;
}
public void Reset() => this.index = 0;
}
}
✅ Lambda discard parameters: ラムダ式で破棄パラメーター
Action<int, string> f = (_, _) => { };
✅ Attributes on local functions: ローカル関数の属性
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Foo() {}
C# 10
✅ Record structs: レコード構造体
record struct S();
readonly record struct ROS();
✅ Improvements of structure types: 構造体型の機能強化
引数なしコンストラクタに対応
struct S
{
public S() { }
}
with
式で構造体型と匿名型に対応
var v1 = new S();
var v2 = v1 with { Value = 2 };
record struct S(int Value, string Name);
✅ Interpolated string handlers: 補間文字列ハンドラー
Foo($"aaa{123}");
void Foo(Handler handler) { }
[InterpolatedStringHandler]
ref struct Handler
{
public Handler(int literalLength, int formattedCount) { }
public void AppendLiteral(string value) { }
public void AppendFormatted<T>(T value) { }
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
public sealed class InterpolatedStringHandlerAttribute : Attribute
{
public InterpolatedStringHandlerAttribute() { }
}
}
✅ global using directives: global using
ディレクティブ
global using Foo.Bar;
Implicit Usings
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Using Remove="System.Net.Http" />
</ItemGroup>
<!-- or -->
<ItemGroup>
<PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>
System.Net.Http
が存在しないため、Using
のRemove
で除外するか、パッケージを参照必要がある。そうでない場合は下記のエラーとなる。
error CS0234: 型または名前空間の名前 'Http' が名前空間 'System.Net' に存在しません (アセンブリ参照があることを確認してください)
✅ File-scoped namespace declaration: ファイルスコープの名前空間宣言
namespace Foo.Bar;
✅ Extended property patterns: 拡張プロパティーパターン
入れ子のプロパティーパターンに対応
var r = x is { PropName1.PropName2: 2 };
✅ Improvements on lambda expressions: ラムダ式の機能強化
ラムダ式の自然型
var f = () => { }; // Action
ラムダ式の戻り値の型指定
var f = int () => 1;
ラムダ式の属性指定
var f3 = [return: NotNull] () => "";
✅ Allow const interpolated strings: 定数の補間文字列
const string S1 = "aaa";
const string S2 = "123";
const string S = $"{S1} {S2}";
✅ Record types can seal ToString(): レコード型で ToString()
をシール
record C()
{
public override sealed string ToString() => "aaa";
}
✅ Improved definite assignment: 限定代入の機能強化
null 状態分析が改善された。
✅ Allow both assignment and declaration in the same deconstruction: 同じ分解内の代入と宣言
var x = 0;
(x, int y) = (1, 2);
✅ Allow AsyncMethodBuilder attribute on methods: メソッドで AsyncMethodBuilder
属性を許可する
[AsyncMethodBuilder(typeof(TaskBuilder))]
async MyTask FooAsync() => await Task.Delay(0);
class TaskBuilder
{
public static TaskBuilder Create() => new();
public MyTask Task => new();
public void SetException(Exception exception) { }
public void SetResult() { }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion
where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
{ }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion
where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
{ }
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
{ }
public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
}
class MyTask { }
✅ CallerArgumentExpression attribute: CallerArgumentExpression
属性
Foo(1.ToString() is { Length: 2 });
void Foo(bool condition, [CallerArgumentExpression(nameof(condition))] string? expression = null)
{
if (!condition)
{
Console.WriteLine($"error: {expression}");
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class CallerArgumentExpressionAttribute : Attribute
{
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}
public string ParameterName { get; }
}
}
✅ Enhanced #line pragma: 拡張 #line
プラグマ
#line 100
Foo();
void Foo([CallerLineNumber] int lineNumber = 0) => Console.WriteLine(lineNumber);
C# 11
✅ Raw string literals: 未加工の文字リテラル
var s =
"""
line1
line2
""";
⛔ Generic math support: ジェネリック数値演算サポート
静的抽象インターフェースメンバーに対応する必要がある。
var values = new int[] { 1, 2, 3 };
Console.WriteLine(Sum(values));
static T Sum<T>(IEnumerable<T> values)
where T : INumber<T>
{
T result = T.Zero;
foreach (var value in values)
{
result += value;
}
return result;
}
✅ Generic attributes: ジェネリック属性
class G<T> : Attribute { }
[G<int>]
class C { }
✅ UTF-8 string literals: UTF-8 文字列リテラル
var data = "abc"u8;
dotnet add package System.Memory
✅ Newlines in string interpolation expressions: 文字列補間の改行
var s = $"aaa{
123
}bbb";
✅ List patterns: リストパターン
var x = new int[] { 1, 2, 3, 4 };
var r = x is [ 1, 2, .. ];
✅ File-local types: ファイルローカル型
file class C { }
✅ Required members: 必須メンバー
var c1 = new C() { Value = 1 };
var c2 = new C(1);
class C
{
public C() { }
[SetsRequiredMembers]
public C(int value)
{
this.Value = value;
}
public required int Value { get; set; }
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class RequiredMemberAttribute : Attribute { }
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
public sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}
public string FeatureName { get; }
public bool IsOptional { get; init; }
public const string RefStructs = nameof(RefStructs);
public const string RequiredMembers = nameof(RequiredMembers);
}
}
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
public sealed class SetsRequiredMembersAttribute : Attribute { }
}
✅ Auto-default structs: 自動デフォルト構造体
struct S
{
int value;
public S() { }
}
✅ Pattern match Span on a constant string: 文字列定数で Span<char>
とパターンマッチ
var s = "foo".AsSpan();
var r = s is "foo";
✅ Extended nameof scope: 拡張 nameof
スコープ
[return: NotNullIfNotNull(nameof(test))]
string? Foo(string? test) => test is not null ? "not null" : null;
❔ Numeric IntPtr: 数値 IntPtr
.NET 7 以降のランタイムの場合、nint
と nuint
の特別扱いをしなくなる。(ジェネリック数値演算の関連)
⛔ ref fields: ref
フィールド
ref struct S
{
ref int value;
}
✅ scoped ref: scoped ref
変数
static Span<byte> Foo(scoped Span<byte> v) => new byte[1];
static Span<byte> Bar(Span<byte> v) => Foo(stackalloc byte[1]);
✅ Improved method group conversion to delegate: メソッドグループからデリゲートへの変換の改善
デリゲートにメソッドを渡すと毎回 new
されていたが、キャッシュされるようになった。
Foo(A);
Foo(() => { });
static void Foo(Action a) => a();
static void A() { }
⛔ Warning wave 7: 警告ウェーブ7
小文字のみの型名を警告するコンパイラ警告の追加。
<AnalysisLevel>7</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
class foo { }
net472
にすると警告が抑制されるようだ。
C# 12
✅ Primary constructors: プライマリコンストラクター
class C(int value)
{
int Value { get; } = value;
}
✅ Collection expressions: コレクション式
int[] values = [ 1, 2, 3 ];
✅ ref readonly parameters: ref readonly
パラメーター
void Foo(ref readonly int value) {}
✅ Default lambda parameters: ラムダ式パラメーターの既定値
var f = (int value = 1) => { };
✅ Alias any type: 任意の型のエイリアス
using Alias = (int x, int y);
var value = new Alias(1, 2);
⛔ Inline arrays: インライン配列
ランタイムレベルの対応が必要。
[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer
{
private int _element0;
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
public sealed class InlineArrayAttribute : Attribute
{
public InlineArrayAttribute(int length)
{
Length = length;
}
public int Length { get; }
}
}
error CS9171: ターゲットのランタイムはインライン配列型をサポートしていません。
✅ Experimental attribute: 試験段階の属性
[Experimental("Foo")]
void Foo() { }
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Assembly |
AttributeTargets.Module |
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Enum |
AttributeTargets.Constructor |
AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Event |
AttributeTargets.Interface |
AttributeTargets.Delegate, Inherited = false)]
public sealed class ExperimentalAttribute : Attribute
{
public ExperimentalAttribute(string diagnosticId)
{
DiagnosticId = diagnosticId;
}
public string DiagnosticId { get; }
public string? UrlFormat { get; set; }
}
}
✅ Interceptors: インターセプター
new C().Foo();
class C
{
public void Foo() => Console.WriteLine("Foo");
}
namespace MyInterceptors
{
static class D
{
[InterceptsLocation(@"<FULL-PATH>\Program.cs", 9, 9)]
public static void Bar(this C instance) => Console.WriteLine("Bar");
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
#pragma warning disable CS9113
public sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute
#pragma warning restore CS9113
{
}
}
<PropertyGroup>
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);MyInterceptors</InterceptorsPreviewNamespaces>
</PropertyGroup>