PowerShellの柔軟過ぎる型変換・キャストに恐れおののく
stuncloudさんがこんな記事を。
PowerShellは暗黙の型変換がんばりすぎ | たっぷす庵
そうそう、PowerShellのキャストって高機能過ぎですよね。
気になったので、その高機能っぷりを調べてみた。
結果
高機能なキャストの動作ですけど、、、
- 対象がstringなら、stringを引数にとるParseメソッド(TryParseは使わない)
- 対応する型のコンストラクター
- 対応する型のキャスト
- どれも失敗なら、stringに変換(多分ToString)してもう一回
ということの模様。
、、、キャスト、最後かよ。
Parseメソッドはstring限定っぽい。
型変換
リテラルは
- ''または""ならstring(""は置換が入る)
- 数字のみならint
- 小数点が入ったらdouble(decimalじゃないのか、、、)
という解釈で、変数の場合はその型で、上記の高機能なキャストが行われるみたい。
スクリプト
確認のため作成したものです。
int二つのコンストラクターと、int配列のコンストラクター。
int二つの配列をキャストするとint配列のコンストラクターが呼ばれるけど、New-Objectするとint二つのが呼ばれる。
int三つの配列をキャストするとint配列のコンストラクターが呼ばれるけど、New-Objectはエラーになる。
ただ、数値二つのオブジェクト配列をキャストするとエラーになるけど、New-Objectはint二つのが呼ばれる。
うーん、統一性が、、、。
$src = @" using System; public class Test { public string StringArg { get; set; } public int IntArg { get; set; } public Test() { Console.WriteLine("Constructor Default"); } public Test(string arg) { Console.Write("Constructor string "); Console.WriteLine(arg); StringArg = arg; } public Test(int arg) { Console.Write("Constructor int "); Console.WriteLine(arg); IntArg = arg; StringArg = IntArg.ToString(); } public Test(double arg) { Console.Write("Constructor double "); Console.WriteLine(arg); StringArg = arg.ToString(); } public Test(int arg1, int arg2) { Console.Write("Constructor int2 "); Console.Write(arg1); Console.Write(" "); Console.WriteLine(arg2); IntArg = arg1 + arg2; StringArg = IntArg.ToString(); } public Test(int[] args) { Console.Write("Constructor int "); Console.WriteLine(args.Length); IntArg = 0; foreach(var arg in args) { IntArg += arg; } StringArg = IntArg.ToString(); } public static Test Parse(string arg) { Console.Write("Parse string "); Console.WriteLine(arg); return new Test(arg); } public static Test Parse(double arg) { Console.Write("Parse double "); Console.WriteLine(arg); return new Test(arg.ToString()); } public static Test Parse(int arg) { Console.Write("Parse int "); Console.WriteLine(arg); return new Test(arg); } public static bool TryParse(string arg, out Test res) { Console.Write("TryParse "); Console.WriteLine(arg); var ret = false; try { res = new Test(arg); ret = true; } catch { res = null; } return ret; } } public class Test2 { public string StringArg2 { get; set; } public int IntArg2 { get; set; } public Test2() { Console.WriteLine("Constructor2 Default"); } public Test2(Test arg) { Console.Write("Constructor2 Test "); Console.WriteLine(arg.IntArg); StringArg2 = arg.StringArg; IntArg2 = arg.IntArg; } public static Test2 Parse(Test arg) { Console.Write("Parse2 "); Console.WriteLine(arg.IntArg); return new Test2(arg); } public static bool TryParse(Test arg, out Test2 res) { Console.Write("TryParse2 "); Console.WriteLine(arg.IntArg); var ret = false; try { res = new Test2(arg); ret = true; } catch { res = null; } return ret; } public static explicit operator Test2(Test arg) { Console.Write("Cast2 "); Console.WriteLine(arg.IntArg); return new Test2(arg); } } "@ Add-Type $src
このスクリプトのメソッド名を変えたり、渡すものを変えて試験しました。