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

わんくま同盟

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

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

ツリー一括表示

構造体のループ処理 /dai (24/04/18(Thu) 10:40) #103070
Re[1]: 構造体のループ処理 /魔界の仮面弁士 (24/04/18(Thu) 11:01) #103071
  └ Re[2]: 構造体のループ処理 /dai (24/04/18(Thu) 11:29) #103072
    ├ Re[3]: 構造体のループ処理 /魔界の仮面弁士 (24/04/18(Thu) 11:59) #103074
    └ Re[3]: 構造体のループ処理 /dai (24/04/18(Thu) 11:54) #103073 解決済み
      └ Re[4]: 構造体のループ処理 /魔界の仮面弁士 (24/04/18(Thu) 12:05) #103075
        └ Re[5]: 構造体のループ処理 /dai (24/04/18(Thu) 13:19) #103076 解決済み


親記事 / ▼[ 103071 ]
■103070 / 親階層)  構造体のループ処理
□投稿者/ dai (1回)-(2024/04/18(Thu) 10:40:00)

分類:[VB.NET/VB2005 以降] 

2024/04/18(Thu) 10:40:40 編集(投稿者)
2024/04/18(Thu) 10:40:33 編集(投稿者)

<pre><pre>VB.NETにて、構造体をForNext指定して処理したいです。

Private objTest1 As ST_TEST
Private objTest2 As ST_TEST
Private objTest3 As ST_TEST

Public Structure ST_TEST
  Public data1 As Decimal
Public data2 As Decimal
Public data3 As Decimal
End Structure

上記のような構造体がある場合objTest1〜3をForNextで処理したいです(下記イメージ)
For i As Integer = 1 To 3
objTest(i).data1 = i
Next


どのようにすれば実現できますか?
ForNextに限らず、数字部分をワイルドカードで指定できる処理などでも構いません
よろしくお願いします</pre></pre>
[ □ Tree ] 返信 編集キー/

▲[ 103070 ] / ▼[ 103072 ]
■103071 / 1階層)  Re[1]: 構造体のループ処理
□投稿者/ 魔界の仮面弁士 (3764回)-(2024/04/18(Thu) 11:01:56)
No103070 (dai さん) に返信
> Private objTest1 As ST_TEST
> Private objTest2 As ST_TEST
> Private objTest3 As ST_TEST

ではなく、
 Private objTest(2) As ST_TEST
もしくは
 Private objTest As ST_TEST() = New ST_TEST(2) {}
としておけば、
 For i = 0 To 2
  objTest(i).data1 = CDec(i + 1)
 Next
と書けます。
[ 親 103070 / □ Tree ] 返信 編集キー/

▲[ 103071 ] / ▼[ 103074 ] ▼[ 103073 ]
■103072 / 2階層)  Re[2]: 構造体のループ処理
□投稿者/ dai (2回)-(2024/04/18(Thu) 11:29:34)
No103071 (魔界の仮面弁士 さん) に返信
ご回答ありがとうございます。

今回既存PGへの処理の追加を行っており、objTest1〜3(実際はobjTest40まである)はすでにいろいろな処理に使われていて、
そちらには手を入れたくない、という背景があります。

コントロールでしたら
For i As Integer = 1 To 3
Dim TestName As String = "objTest" & i
Controls(TestName).Text = "任意"
Next
のようにできるかと思いますが、
構造体を上記のように文字列から指定して処理する、みたいなことはできないでしょうか?

引き続きお力添えいただければ幸いです。

新規の構造体を作成する際には先ほどの回答を参考にさせていただきます。ありがとうございます。
[ 親 103070 / □ Tree ] 返信 編集キー/

▲[ 103072 ] / 返信無し
■103074 / 3階層)  Re[3]: 構造体のループ処理
□投稿者/ 魔界の仮面弁士 (3765回)-(2024/04/18(Thu) 11:59:26)
2024/04/18(Thu) 12:03:22 編集(投稿者)

No103072 (dai さん) に返信
> 今回既存PGへの処理の追加を行っており、objTest1〜3(実際はobjTest40まである)はすでにいろいろな処理に使われていて、
> そちらには手を入れたくない、という背景があります。

構造体である以上、設定後に書き戻す処理が発生してしまうことになると思います。

Dim o() = {Nothing, objTest1, objTest2, objTest3}

'ループ処理
For i = 1 To 3
  o(i).data1 = CDec(i)
Next

objTest1 = o(1)
objTest2 = o(2)
objTest3 = o(3)



相手が Class なら、
 Choose(i, objTest1, objTest2, objTest3).data1 = CDec(i)
などといった手も使えるのですけれどね。

相手が Structure となると、CallByName やリフレクションでもどうにもならないと思います。
https://smdn.jp/programming/netfx/tips/set_struct_field_using_reflection/

VB の Choose 関数が、VB2017 で実装された「ByRef 戻り値」を採用しているなら
 Choose(i, objTest1, objTest2, objTest3).data1 = CDec(i)
みたいに書けるかとも思ったものの、参照渡しな可変個引数がサポートされていない以上、どっちにしても NG 。



あと思いつくのは、デリゲートで操作できるようなヘルパーを用意するとか…?

Friend Delegate Sub TestProc(ByRef t As ST_TEST)
Friend Sub Helper(index As Integer, proc As TestProc)
 Select Case index
  Case 1 : proc(objTest1)
  Case 2 : proc(objTest2)
  Case 3 : proc(objTest3)
 End Select
End Sub

Sub Main()
 For i = 1 To 3
  Dim value = CDec(i)
  Helper(i, Sub(ByRef o) o.data1 = value)
 Next
 Stop
End Sub
[ 親 103070 / □ Tree ] 返信 編集キー/

▲[ 103072 ] / ▼[ 103075 ]
■103073 / 3階層)  Re[3]: 構造体のループ処理
□投稿者/ dai (3回)-(2024/04/18(Thu) 11:54:42)
2024/04/18(Thu) 11:55:12 編集(投稿者)

No103072 (dai さん) に返信
> ■No103071 (魔界の仮面弁士 さん) に返信

既存のobjTest1〜3を、Private objTest As ST_TEST() = New ST_TEST(2) に突っ込めば実現できそうですね。

すみません。ありがとうございました!
解決済み
[ 親 103070 / □ Tree ] 返信 編集キー/

▲[ 103073 ] / ▼[ 103076 ]
■103075 / 4階層)  Re[4]: 構造体のループ処理
□投稿者/ 魔界の仮面弁士 (3766回)-(2024/04/18(Thu) 12:05:22)
2024/04/18(Thu) 12:49:02 編集(投稿者)

No103073 (dai さん) に返信
> 既存のobjTest1〜3を、Private objTest As ST_TEST() = New ST_TEST(2) に突っ込めば実現できそうですね。

ST_TEST がクラスならばそれで良いですけれど、
ST_TEST が構造体である以上、メンバーの値を操作しても
書き換わるのは objTest 内のインスタンスだけで、
元の objTest1 〜 objTest3 の内容は変化しませんが、その点は大丈夫ですか?


実際には 40 個もあるらしいので、
「objTest 配列の中身を、objTest1〜40 に書き戻すメソッド」
を用意して、それを終了処理として呼び出すという手はありますが…
書き戻す処理を忘れてしまうと大変です。

objTest 配列を経由していない既存処理との連携で齟齬が生じてしまうので、
そうならないように、配列操作後には必ず書き戻し処理が必須という
制約が付いてまわることになります。書き戻し処理を呼び忘れても
コンパイル時には検出されないので、特に注意が必要ですね。


リファクタリングが許されるなら、既存の objTest1 への操作を撤廃し、
すべて objTest(1) への操作に書き換えた方が安全かも知れません。

※インデックスがズレると分かりにくいので、objTest(0) は未使用とする。
[ 親 103070 / □ Tree ] 返信 編集キー/

▲[ 103075 ] / 返信無し
■103076 / 5階層)  Re[5]: 構造体のループ処理
□投稿者/ dai (4回)-(2024/04/18(Thu) 13:19:56)
No103075 (魔界の仮面弁士 さん) に返信
> 2024/04/18(Thu) 12:49:02 編集(投稿者)

一度PLに相談の上、リファクタリングするか書き戻す処理を作成するか考えたいと思います。
(リファクタリングした方が他のコードもスッキリしそうなので、そちらを推していきたいと思います)

また、Classの場合の処理例などもとても勉強になりました。
今後同様の処理が必要になった際の選択肢が広がりました。ありがとうございます。
解決済み
[ 親 103070 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -