C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

C# こわい話: LINQ でパスのサニタイズしたくらいでテストが通らないなんてそんな事が

起きた😅

現象

f:id:USAGI-WRP:20190225125342p:plain

  public static class x
  {
    public static string f( string input )
    {
      var targets = Path.GetInvalidFileNameChars();
      var intermediate = 
        from c in input where !targets.Contains( c ) select c;
      var result = string.Concat( intermediate ); // <-- 予想外の結果が生じていた
      return result;
    }
  }

input"Death Sauce \n\r 02:00:00" を与えてテストしたら "Death Sauce 020000" が Expected 、と思ったんだけど、実際に出たのは "System.Linq.Enumerable+WhereEnumerableIterator1[System.Char]"` でした💀

対策

f:id:USAGI-WRP:20190225125313p:plain

      var result = new string( intermediate.ToArray() );

stringchar[] からのコンストラクターを持っているのでこれで Actual == Expected へ。

この問題に気づいて初め、ほぼワンライナー程度の実装なのでテスト側のコードにべたっと書いてデバッガー挿したら期待動作しちゃったんだよね。ぇー…って思って wandbox で最小コード切り出して叩いても期待動作して再現しないし。

ローカル環境では放り込むアセンブリーの単位を変えたら発症したので、そこらへんに理由があって、古い .NET Framework ターゲットでは string.Concatオーバーロード解決がナウい処理系とは異なるとかなのかな。もっと単純に何か私がミスしてるのかな🤔

回避方法は上記の通り簡単だし、この処理はボトルネックでもなんでもないのでさくっと回避して通り過ぎる事にしたけれど、お気持ちは少々もんにょりが残る。なんじゃろ。