1. ホーム
  2. c#

[解決済み] Roslyn がコードのコンパイルに失敗した

2023-02-05 23:29:10

質問

プロジェクトを VS2013 から VS2015 に移行した後、プロジェクトがビルドされなくなりました。 以下の LINQ ステートメントでコンパイルエラーが発生します。

static void Main(string[] args)
{
    decimal a, b;
    IEnumerable<dynamic> array = new string[] { "10", "20", "30" };
    var result = (from v in array
                  where decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b // Error here
                  orderby decimal.Parse(v)
                  select v).ToArray();
}

コンパイラはエラーを返します。

エラー CS0165 未割り当てのローカル変数 'b' の使用

この問題の原因は何でしょうか? また、コンパイラの設定によって修正することは可能でしょうか?

どのように解決するのですか?

この問題の原因は何ですか?

私にはコンパイラのバグのように見えます。少なくとも、それはそうでした。しかし decimal.TryParse(v, out a)decimal.TryParse(v, out b) の式は動的に評価されるため、I が期待される に到達するまでに、コンパイラはまだそれを理解していると期待します。 a <= b に到達するまでに、両方の ab は間違いなく代入されます。動的型付けで変なことを思いついたとしても、私はこれまで a <= b の両方を評価した後に TryParse の両方の呼び出しを評価した後です。

しかし、演算子と変換のトリッキーさによって、式 A && B && C を評価する AC ではなく B - でなく、狡猾であれば を参照してください。 Roslynバグレポート Neal Gafterの独創的な例を参照してください。

を使ってそれを動作させる dynamic オペランドが動的な場合のセマンティクスを説明するのは困難です。オーバーロードの解決を行うには、オペランドを評価して関係する型を見つける必要があり、直感に反する場合があるからです。しかし、またしても Neal 氏は、コンパイラ・エラーが必要であることを示す例を思いつきました...これはバグではなく、バグです 修正 . それを証明した Neal に多大な賞賛を送ります。

<ブロッククオート

コンパイラの設定によって修正することは可能でしょうか?

いいえ、しかし、このエラーを回避する代替手段があります。

まず、動的でないようにすることができます。もし文字列しか使わないことが分かっているのであれば IEnumerable<string> または 範囲変数を与える v の型は string (すなわち from string v in array ). それが私の望ましい選択肢です。

もしあなたが 本当に が必要な場合は b に値を与えるだけです。

decimal a, b = 0m;

これは何の害もありません。 実際に に値を割り当てることになります。 b に値を割り当てることになり、初期値は無関係になります。

さらに、括弧をつけるのも効果的なようです。

where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)

これは、オーバーロードの解決の様々な部分がトリガーされる時点を変更し、コンパイラを喜ばせることになります。

そこには 1 つ による確定的な割り当てに関する仕様の規則です。 && 演算子による定型代入に関する規則を明確化する必要があります。 && 演算子が 2 つの bool オペランドで使用されています。次の ECMA 標準ではこれが修正されていることを確認しようと思います。