ジェネリックでnameof
を試してみました。期待した結果が得られませんでした。これが仕様の一部であるかどうかはわかりません。
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ($"Hello { nameof(FooBar<string>)! }");
}
}
class FooBar<T> { }
私が得る出力は
こんにちはFooBar!
型パラメーターについての詳細を期待します。
私はそれをメソッドで試しましたが、コンパイラエラーで失敗しました:
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ($"Hello { nameof(Do<string>) }");
}
public static T Do<T>() {}
}
エラーCS8084:nameof演算子への引数は、型引数(CS8084)(foo)を持つメソッドグループであってはなりません
これは、nameof
がコンパイル時の構成要素であり、ジェネリックスが実行時に初期化される型であるためですか?それとも他の制限がありますか?
型パラメーターについての詳細を期待します
nameofの結果。nameofの結果は、その引数がバインドされたシンボルによって異なります。
1つ以上のメンバー:すべてのメンバーが同じメタデータ名を持つ場合、nameofの結果はその名前になります。そうでない場合、「この引数は異なる名前の複数の要素を参照しています」というエラーになります。メンバーのメタデータ名I
or
I <isA1 ... AK> `は、標準の識別子変換が適用された後は単に「I」になります。
<T>
パラメータは、<>
を有効な識別子として許可しない標準の識別子変換(C#仕様のセクション§2.4.2)により削除されました。最初に先頭の@が削除され、次にUnicodeエスケープシーケンスが変換されてから、フォーマット文字が削除されます。もちろん、これはコンパイル時にも発生します。ジェネリック型の名前を出力しようとすると、これも確認できます。
typeof(List<string>).Name;
結果は:
List`1
これは、nameofがコンパイル時の構成体であり、ジェネリックスが実行時に初期化される型であるためですか?それとも他の制限がありますか?
2番目のエラーは、nameof
内の過負荷解決の複雑化を回避するために、設計上無効と指定されています。
ジェネリック型の引数を許可しますか?型に名前を付ける場合は、おそらく「はい」です。これは、式バインディングがすでに機能しているためです。そしておそらく 'いいえ'。型引数はオーバーロードの解決中に使用/推論されるため、メソッドグループに名前を付けるとき、nameofでそれを処理する必要があると混乱するでしょう。
Roslynコードベースでそれを明確に見ることができます:
private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax node,
DiagnosticBag diagnostics)
{
CheckFeatureAvailability(node.GetLocation(), MessageID.IDS_FeatureNameof, diagnostics);
var argument = node.ArgumentList.Arguments[0].Expression;
string name = "";
// We relax the instance-vs-static requirement for top-level member access expressions by creating a NameofBinder binder.
var nameofBinder = new NameofBinder(argument, this);
var boundArgument = nameofBinder.BindExpression(argument, diagnostics);
if (!boundArgument.HasAnyErrors && CheckSyntaxForNameofArgument(argument, out name, diagnostics) && boundArgument.Kind == BoundKind.MethodGroup)
{
var methodGroup = (BoundMethodGroup)boundArgument;
if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty)
{
// method group with type parameters not allowed
diagnostics.Add(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, argument.Location);
}
else
{
nameofBinder.EnsureNameofExpressionSymbols(methodGroup, diagnostics);
}
}
return new BoundNameOfOperator(node, boundArgument, ConstantValue.Create(name), Compilation.GetSpecialType(SpecialType.System_String));
}