前提・実現したいこと
オブジェクトを配列にして使っているのですが
インデックスの指定に数値とNameの両方が使えるようにしたいのです
何を利用したらいいのでしょうか
FormのControls 等 目にする機会は多いのですが
作り方が全く分かりません。
お願い致します。
該当のソースコード
powershell
1Using NameSpace System.Windows.Forms 2 3$Form = [Form]::new() 4 5for ($i=0;$i-le9;$i++) 6{ 7 [TextBox]::new() | 8 %{ 9 $_.Name = "TextBox_$i" 10 $Form.Controls.Add($_) 11 } 12} 13 14<# 15 どちらの方法でも取得できる 16 こんな感じで使えるコレクション?を作りたい 17#> 18Write-Host $($Form.Controls["TextBox_5"].Name) -ForegroundColor Red 19Write-Host $($Form.Controls[5].Name) -ForegroundColor Red
試したこと
現状だとディクショナリ 使って名前で指定できるようにして
数値で指定したくなったらValueでArray(object[])にするしか.....
PowerShellのクラスのプロパティでAdd-memberを使って
ゲッターセッター風にすることはできるですが
クラスのメンバーを追加するだけなので....
クラスのインスタンス自身にインデクサ?を指定されたときの振る舞いを
変えることは出来ないですし
powershellだと出来ないってことでしょうか?(Add-type で C#取り込み除く)
powershell
1Using NameSpace System.Collections.Generic 2Using NameSpace System.Management.Automation 3 4$Dic = [Dictionary[String,PSCustomObject]]::new() 5 6$Ar = 0..9 | 7%{ 8 [PSCustomObject]@{ 9 Name = "Name$_" 10 Text = "Text_$_" 11 Disp = "テキスト_$_" 12 } 13} 14 15$Ar | 16%{ 17 $Dic.Add($_.Name,$_) 18} 19 20 21Write-host $Dic["Name5"].Name -ForegroundColor Red 22Write-host $($Dic.Values)[5].Name -ForegroundColor Red
補足情報(FW/ツールのバージョンなど)
Win10
powershell 5.1
例えばインデクサを二つ持つクラスを Add-Type で C# で作成し、それをプロパティとして持たせるというのもダメでしょうか?
質問文
> powershellだと出来ないってことでしょうか?(Add-type
> で C#取り込み除く)
ですね
何年も気になっていたので質問したのですが
考え直しても 使えたら便利ですけど無くてもそこまで困るものでもないと思ったので
やりたかったらAdd-type 使うしかないのであれば
諦めます。
リフレクションを作って動的に型を作れば PowerShell だけでできないことはありません。
不必要に面倒になりますが。
TypeBuilder を使ってこんな感じでやりますが、IL を自分で書くか式木を組み立てるかの選択で、どっちも超めんどくさいです。
http://www.moonmile.net/blog/archives/8683
少し簡単にするには、C# で書いてコンパイルしてそれをディスアセンブルするということになりますが、それだと本末転倒な気もします。
ありがとうございます。
リフレクション...ですか
前にリフレクションを使ってWinApi使う方法を見たことがありますが、それもかなり面倒なことになっていました....
リフレクション 自体何なのか全く分かっていませんが
それに関わると恐ろしいことになるのはよく分かりました。
C# を利用する以上に簡単な方法はない
ということでいいのでしょうか。
リフレクション自体は「少し面倒」くらいです。ただこの場合は動的メソッドを作らなければいけないので、普通のリフレクションの 100 倍面倒だと思っていただければ。要するにコンパイラのするべき仕事を手作業でするということです。
私はこの場合は C# が一番手軽だと思っていますし、ざっと検索してみてもインデクサについての情報はみつかりませんでしたが、知的好奇心ということであれば、よく探せばもしかしたら何かあるかもしれません。
また、インデクサ実体はメソッドなので、オブジェクトを引数とする ScriptMethod を作り、その内部でどうにかすれば似たようなことはできるかもしれません。その場合、取得は
o.Items("John")
o.Items(2)
設定は
o.SetItem("John")
のような形になります。
スクリプトメソッドの中では $this で自身のオブジェクトを取得できるので、データ自体は NoteProperty か何かで持たせておくことになります。
https://docs.microsoft.com/ja-jp/dotnet/api/system.dynamic.dynamicobject?view=netframework-4.7.2
そういえば DynamicObject というものがありました。
これを継承すれば思い通りのものができるかもしれません。
> インデクサ実体はメソッド
ということは インデクサは既定のメソッド っていう感じでしょうか?
PowerShell のクラスで 既定のメソッド、又はプロパティって指定出来るのでしょうか?
一先ず教えて頂いたDynamicObject の使い方を確認するために
例文をそのまま powershell で書き直そうとしたのですが
out や override の文法の代替?が分からず
使えませんでした。
```powershell
Using NameSpace System
Using NameSpace System.Dynamic
Using NameSpace System.Collections.Generic
class DynamicDictionary : DynamicObject
{
[Dictionary[string, System.Object]] $dictionary = [Dictionary[string, Object]]::new()
[int] Count ()
{
return $This.dictionary.Count
}
<#
既定のメソッドと思われるが powerShell で
C# の 「public override」
と同じ役割をする文法が分からない
#>
[bool] TryGetMember (
[GetMemberBinder] $binder, [Object] $result)
{
[string] $name = $binder.Name.ToLower()
return $This.dictionary.TryGetValue($name,$result)
}
# 上に同じく
[bool] TrySetMember(
[SetMemberBinder] $binder, [Object] $value)
{
$This.dictionary[$binder.Name.ToLower()] = $value
return $true
}
}
class Program
{
static [void] Main([string[]] $args)
{
[DynamicDictionary] $person = [DynamicDictionary]::new()
<#
FirstName と LastName
どっから降って湧いたのかわからない....
定義してない....
そしてやっぱり使えない
とゆうか $args どこ行ったの....?
#>
$person.FirstName = "Ellen"
$person.LastName = "Adams"
Write-Host "$($person.firstname) $($person.lastname)"
Write-Host "Number of dynamic properties: $($person.Count)"
}
}
clear
[Program]::Main(@("A","B","C","D","E"))
```
既定のメソッドではなくインデクサとして定義されたプロパティから呼ばれるメソッドです。PowerShell の Class 構文では定義できないみたいですね。
DynamicObject も C# の言語機能が必要だったようで使えませんでした。
なるほど...
でも 勉強になりました。
OrderedDictionary が使えることが分かったので
そちらを使ってみることにします。
今回もありがとうございました。
回答2件
あなたの回答
tips
プレビュー