C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

PowerShellで変数の中身を実行させたい

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■91182 / inTopicNo.1)  PowerShellで変数の中身を実行させたい
  
□投稿者/ pe (1回)-(2019/06/05(Wed) 20:18:10)

分類:[.NET 全般] 

(Get-Process).Companyとやると会社一覧が表示されます。

$comp = "Company"
(Get-Process).$comp
このようにやっても動きます。なぜでしょうか?
他の言語だと動かないと思うのですが、PowerShellだと何故動くのでしょうか?
引用返信 編集キー/
■91203 / inTopicNo.2)  Re[1]: PowerShellで変数の中身を実行させたい
□投稿者/ Hongliang (818回)-(2019/06/06(Thu) 09:48:24)
> このようにやっても動きます。なぜでしょうか?
なぜ、と言われると、それができるように設計したからとしか言えないと思いますが…。
文法解析的には、変数の識別子を$開始と決めたために、メンバ名と識別できるから、その記述を認めても問題なくなった、とか。

> 他の言語だと動かないと思うのですが
動的言語では似たような記述が可能なのもそれなりにあるんじゃないでしょうか?
例えばJavaScriptだと、以下のような記述が可能です。

let obj = { prop: 'ok', name: 'ng' };
let name = 'prop';
console.log(obj[name]); // okが出力される

// obj.name だとnameがobjのメンバなのか変数なのか区別できないので
// . 演算子の右辺で変数を使うことはできない
引用返信 編集キー/
■91208 / inTopicNo.3)  Re[1]: PowerShellで変数の中身を実行させたい
□投稿者/ はまぐり (75回)-(2019/06/06(Thu) 10:18:21)
No91182 (pe さん) に返信

Bashでも同じように動作します
Bashにはオブジェクトという概念はありませんが
変数を展開した文字列をコマンドとして実行できます

PowerShellやBashに共通することはコマンドラインインタプリタであることです
コマンドラインインタプリタはコマンドを実行することを主目的にしてるので
言語の用途としてそのようにした方が都合が良かったのじゃないかなと思いました
引用返信 編集キー/
■91281 / inTopicNo.4)  Re[1]: PowerShellで変数の中身を実行させたい
□投稿者/ 魔界の仮面弁士 (2202回)-(2019/06/11(Tue) 11:37:57)
No91182 (pe さん) に返信
> (Get-Process).Companyとやると会社一覧が表示されます。
> $comp = "Company"
> (Get-Process).$comp
> このようにやっても動きます。なぜでしょうか?
> 他の言語だと動かないと思うのですが、PowerShellだと何故動くのでしょうか?

System.Dynamic.ExpandoObject クラスや
System.Dynamic.DynamicObject クラスはご存知でしょうか。
https://blog.okazuki.jp/entry/20100808/1281239670

PowerShell のオブジェクト(PSObject / PSCustomObject)は、
この ExpandoObject に相当する機能を有しているようです。



たとえば C# で下記を参照設定してみます。
"C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll"

そうすると、C# から
 System.Management.Automation.PSObject クラス
が使えるようになります。
https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/MshObject.cs#L48
https://docs.microsoft.com/ja-jp/dotnet/api/system.management.automation.psobject


C# ではこの PSObject クラスを
 // using System.Management.Automation;
 // using System.Dynamic;
 // using System.Linq.Expressions;
 var obj0 = new PSObject();
 var obj1 = new PSObject(123);
 var obj2 = new PSObject("OK");
 var obj3 = new PSObject(DateTime.Now);
のようにして初期化できます。

上記のコードは、PowerShell にとっては、
 $obj0 = New-Object PSObject;
 $obj1 = New-Object PSObject 123;
 $obj2 = New-Object PSObject "OK";
 $obj3 = New-Object PSObject ([DateTime]::Now);
にあたりますが、PowerShell の文法上は、
 $obj1 = 123;
 $obj2 = "OK";
 $obj3 = [DateTime]::Now;
と書くこともできますね。
(PowerShell 側では、PSObject の存在を意識させないよう隠蔽されていますが)



そして PowerShell では、プロパティやメソッドを呼び出すために、
 $obj3.Second;
 $obj3.ToShortDateString();
と直接書くだけでなく、文字列指定で
 $s1 = "Second";
 $s2 = "ToShortDateString";
 $obj3.$s1;
 $obj3.$s2();
のようにしても呼び出せるような簡易的な文法設計になっていますが、
内部処理上はいずれも、PSObject の機能を呼び出しているものと考えられます。


C# から PSObject を直接利用する場合は、
下記のように書くことで動的なメンバー呼び出しが可能です。

PSObject obj4 = new PSObject(DateTime.Now);
dynamic obj5 = obj4;
textBox1.Text = obj5.Second.ToString();
textBox2.Text = obj5.ToShortDateString();

string s1 = "Second";
string s2 = "ToShortDateString";
textBox3.Text = obj4.Members[s1].ToString();
textBox4.Text = obj4.Members[s2].ToString();

label1.Text = obj4.Properties[s1].Value.ToString();
label2.Text = obj4.Methods[s2].Invoke().ToString();

label3.Text = obj4.Members[s1].Value.ToString();
label4.Text = ((PSMethod)obj4.Members[s2]).Invoke().ToString();
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ