[Bug]: Nullable implicit operator on string extensible enums still throws for a null string

オープン 初心者向け
#12,572 コメント 1 件 リアクション 1 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
84/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
csharp
領域
backend, tooling

調査の方向性

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ExtensibleEnumProvider.cs の190~196行付近にある nullable implicit operator の出力箇所から始め、関連するテストを TestProjects/Local.Tests/ExtensibleEnumTests.cs で確認してください。null の文字列変数を StringExtensibleEnum? に変換し、null が返ることを確認するテストを追加してください。出力される operator の null 分岐には nullable enum 型を指定する必要があります。

索引モデルが issue の本文から書いたものです。

説明

bug emitter:client:csharp
Describe the bug

#7966 still reproduces after #7967. Converting a null string to a nullable string extensible enum throws ArgumentNullException instead of returning null. The operator added in #7967 is emitted as:

public static implicit operator StringExtensibleEnum?(string value) => value == null ? null : new StringExtensibleEnum(value);

The conditional's natural type is StringExtensibleEnum, not StringExtensibleEnum?: the untyped null converts to it through the generated implicit operator StringExtensibleEnum(string). So the null branch calls that operator with null, and the constructor's Argument.AssertNotNull throws.

The tests added in #7967 pass because they only use the null literal (NullableExtensibleEnumMethod(null), StringExtensibleEnum? nullFoo = null;). C# converts a null literal to Nullable<T> directly, so neither test calls the new operator.

Every string extensible enum emitted since #7967 has this operator. Azure.ResourceManager.Search hand-wrote a corrected copy for one of its enums to get null handling to work (discussion).

Suggested fix: in ExtensibleEnumProvider.cs, give the null branch the nullable type, e.g. Null.CastTo(Type.WithNullable(true)), so the output becomes value == null ? (StringExtensibleEnum?)null : new StringExtensibleEnum(value).

Reproduction

StringExtensibleEnum below has the same constructor and implicit operators as the generated StringExtensibleEnum.cs, with Argument.AssertNotNull inlined so it runs standalone.

using System;

string value = null;

try
{
    StringExtensibleEnum? e = value;
    Console.WriteLine($"HasValue={e.HasValue}");
}
catch (ArgumentNullException ex)
{
    Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}

public readonly struct StringExtensibleEnum
{
    private readonly string _value;

    public StringExtensibleEnum(string value)
    {
        _value = value ?? throw new ArgumentNullException(nameof(value));
    }

    public static implicit operator StringExtensibleEnum(string value) => new StringExtensibleEnum(value);

    public static implicit operator StringExtensibleEnum?(string value) => value == null ? null : new StringExtensibleEnum(value);
}

Output on .NET 8:

ArgumentNullException: Value cannot be null. (Parameter 'value')

With the null branch cast to (StringExtensibleEnum?)null, it prints HasValue=False.

A test in TestProjects/Local.Tests/ExtensibleEnumTests.cs that exercises the operator:

[Test]
public void ConvertingNullStringToNullableExtensibleEnumDoesNotThrow()
{
    string? value = null;
    StringExtensibleEnum? e = value;
    Assert.IsNull(e);
}
Checklist

🤖 m-nash-copilot

主要言語
Java
スター
5.9k
フォーク
421
平均マージ
2日 3時間
マージ済み PR(30日)
176

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/typespec のほかの issue

microsoft/typespec の issue をすべて見る

似ている issue

Java の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。