C#スクリプト(csi.exe)で定義済みのグローバル変数一覧

C#スクリプトでは呼び出し側でグローバル変数・関数(実際はメソッド)を設定することができます。
標準のスクリプティング環境としてcsi.exeでも使いやすいものがいくつか用意されています。

csi.exeの使い方はこちら
[csiでC#スクリプト](http://www.buildinsider.net/language/csharpscript/01)
Visual Studio 2017だと
`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Roslyn\csi.exe`
になっているようです。


## Args
普通のC#でいう`Main(string[] args)`の`args`のようなものです。
`args`は`string[]`ですが`Args`は`IList<string>(List<string>)`です。


```csharp:qiita.csx
Args.Add("2");
Print(Args);
```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx hoge fuga 1
List<string>(4) { "hoge", "fuga", "1", "2" }
```

## Print
C#には標準出力用に`Console.WriteLine`というメソッドが用意されています。
しかし、csi.exeにはPrintという関数が別に定義されています。
出力を比べてみます。

```csharp:qiita.csx
void WriteDouble(object o) { System.Console.WriteLine(o); Print(o); }

WriteDouble(100);
WriteDouble(200.0);
WriteDouble('あ');
WriteDouble("string");
```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
100
100
200
200
あ
'あ'
string
"string"
```

int,doubleでは同じ出力、char,stringではクォーテーションでくくられた出力という違いですね。
これだけならあまり意味のないように思えます。
次の例だとどうでしょうか。

```csharp:qiita.csx
void WriteDouble(object o) { System.Console.WriteLine(o); Print(o); }

WriteDouble(new []{9,6,9,6,3,2,1});
WriteDouble(new List<string>{"3", "Billion", "Devices", "Run", "Java"});
WriteDouble(new[] { 2, 3, 5, 7, 11, 13, 17 }.Select(i => i * i));

```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
System.Int32[]
int[7] { 9, 6, 9, 6, 3, 2, 1 }
System.Collections.Generic.List`1[System.String]
List<string>(5) { "3", "Billion", "Devices", "Run", "Java" }
System.Linq.Enumerable+WhereSelectArrayIterator`2[System.Int32,System.Int32]
Enumerable.WhereSelectArrayIterator<int, int> { 4, 9, 25, 49, 121, 169, 289 }
```

`Console.WriteLine`ではクラス名が表示される微妙な出力が`Print`ではいい感じに整形されて表示されていますね。
PHPのvar_dumpなどに近い雰囲気です。
さらにクラスを出力してみます。

```csharp:qiita.csx
void WriteDouble(object o) { System.Console.WriteLine(o); Print(o); }
WriteDouble(Encoding.UTF8);
WriteDouble(new Hoge { Index = 2, Name = "ほげ" });
WriteDouble(new { Index = 5, Name = "名無し" });
WriteDouble(new Fuga());

class Hoge
{
    public static string hoge = "hoge";
    public const string fuga = "fuga";
    public string foo = "foo";
    private int pI;
    public int Index { set => pI = value; get => pI; }
    public string Name { set; get; }
}
class Fuga : IEnumerable<int>
{
    public IEnumerator<int> GetEnumerator()
    {
        yield return 1;
        yield return 2;
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
System.Text.UTF8Encoding
UTF8Encoding { BodyName="utf-8", CodePage=65001, DecoderFallback=DecoderReplacementFallback { DefaultString="?", MaxCharCount=1, MaxCharCount=1 }, EncoderFallback=EncoderReplacementFallback { DefaultString="?", MaxCharCount=1, MaxCharCount=1 }, EncodingName="Unicode (UTF-8)", HeaderName="utf-8", IsBrowserDisplay=true, IsBrowserSave=true, IsMailNewsDisplay=true, IsMailNewsSave=true, IsReadOnly=true, IsSingleByte=false, WebName="utf-8", WindowsCodePage=1200 }
Submission#0+Hoge
Submission#0.Hoge { foo="foo", Index=2, Name="ほげ" }
{ Index = 5, Name = 名無し }
<>f__AnonymousType0#1<int, string>(\{ Index = 5, Name = "名無し" })
Submission#0+Fuga
Submission#0.Fuga { 1, 2 }
```

publicなフィールド・プロパティを自動で表示してくれます。IEnumerableの場合はプロパティを表示しないかわりに、中身を展開して表示していますね。

スクリプトでいちいち書かなくても良いので非常に使い勝手が良いでしょう。

## PrintOptions

### MaximumOutputLength

出力する文字列の長さを設定します。
初期値は1024です。

### Ellipsis 

MaximumOutputLengthを超えた箇所の省略で表示する文字列です。
初期値は"..."です。

```csharp:qiita.csx
var h = new Hoge();
Print(h);
PrintOptions.Ellipsis = "以下略";
PrintOptions.MaximumOutputLength = 50;
Print(h);
class Hoge
{
    public int Index { set; get; } = 10;
    public string Name { set; get; } = new string('l', 200000);
}
```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
Submission#0.Hoge { Index=10, Name="llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll...
Submission#0.Hoge { Index=10, Name="llllllllllllll以下略
```

### NumberRadix

整数の出力を切り替えます。初期値は10。
設定できるのは10進数と16進数のみで、2進数などはできないようです。無念。

```csharp:qiita.csx
var h = new Hoge();
Print(h);
PrintOptions.NumberRadix = 16;
Print(h);
class Hoge
{
    public byte Byte { set; get; } = 255;
    public int Int32 { set; get; } = -1;
    public ulong UInt64 { set; get; } = 1474836472147483647;
    public double Double { set; get; } = 1.11;
}
```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
Submission#0.Hoge { Byte=255, Double=1.11, Int32=-1, UInt64=1474836472147483647 }
Submission#0.Hoge { Byte=0xff, Double=1.11, Int32=0xffffffff, UInt64=0x1477abf518241bff }
```

### EscapeNonPrintableCharacters 
制御文字をエスケープして表示するかどうかを設定します。初期値はtrue。
下記のサンプルを見るのが早いでしょう。

```csharp:qiita.csx
var h = new Hoge();
Print(h);
PrintOptions.EscapeNonPrintableCharacters = false;
Print(h);
class Hoge
{
    public char Null { get; } = '\0';
    public string Data { get; } = "h\r\no\tg\0e";
}
```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
Submission#0.Hoge { Data="h\r\no\tg\0e", Null='\0' }
Submission#0.Hoge { Data=@"h
o       g e", Null=' ' }
```

### MemberDisplayFormat

表示形式を設定します。
設定できるものは以下の通りです。
変更にDLL参照が必要なこともあり他の設定に比べると使う機会は少なそうです。

* SingleLine  
一行に全メンバを表示する。初期値。
* SeparateLines  
メンバごとに改行する。
* Hidden  
メンバを表示しない。

```csharp:qiita.csx
#r "Microsoft.CodeAnalysis.CSharp.Scripting.dll"
var h = new Hoge();
Print(h);
PrintOptions.MemberDisplayFormat = Microsoft.CodeAnalysis.Scripting.Hosting.MemberDisplayFormat.SeparateLines;
Print(h);
PrintOptions.MemberDisplayFormat = Microsoft.CodeAnalysis.Scripting.Hosting.MemberDisplayFormat.Hidden;
Print(h);
class Hoge
{
    public int Index { get; } = 20;
    public string Data { get; } = "hoge";
}
```

```:出力結果
PS C:\Test> csi.exe .\qiita.csx
Submission#0.Hoge { Data="hoge", Index=20 }
Submission#0.Hoge {
  Data: "hoge",
  Index: 20
}

Submission#0.Hoge
```


## SourcePaths

## ReferencePaths

SourcePaths,ReferencePathsはインタラクティブ(csx引数なしのcsi.exe呼び出し)でのみ使えます。
使い方はよくわかりませんでしたので、詳しい方がいらっしゃったら解説をお願いします。

## 参考サイト
https://github.com/dotnet/roslyn/blob/master/src/Scripting/Core/Hosting/InteractiveScriptGlobals.cs
https://github.com/dotnet/roslyn/blob/master/src/Scripting/Core/Hosting/CommandLine/CommandLineScriptGlobals.cs