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

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

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

Re[29]: 【VB2005、VB.NET】構造体のコピーについて [2]


(過去ログ 109 を表示中)

[トピック内 49 記事 (41 - 49 表示)]  << 0 | 1 | 2 >>

■65034 / inTopicNo.41)  Re[29]: 【VB2005、VB.NET】構造体のコピーについて
  
□投稿者/ 魔界の仮面弁士 (143回)-(2013/01/30(Wed) 13:15:05)
No65033 (コンバート後に悩む人 さん) に返信
> #前述の話題ですが、Midだから+1ですよね。

そのとおりです。
Len(a3) ではなく、Len(a5) + 1 ですね。失礼しました。(^^;


> substringでしたら0スタートなので+1の心配はしなくてよいということをすっかり失念してました。
Substring だと、データ長を超える位置を指定したときに例外を発するため、
意図的に Strings.Mid を使っていました。


> 以下のような感じでしょうか。

さらに言えば、元の String→Structure のコードは、

Public Function StructureFromString(Of T As Structure)(ByVal s As String) As T
 Dim newValue As ValueType = StructureFromString
 s &= StrDup(Len(newValue), " "c)
 Dim pos As Integer = 1
 For Each f As FieldInfo In newValue.GetType().GetFields()
  Dim attributes() As Object = f.GetCustomAttributes(GetType(VBFixedStringAttribute), False)
  If attributes.Length <> 0 Then
   Dim attr As VBFixedStringAttribute = DirectCast(attributes(0), VBFixedStringAttribute)
   Dim value As String = Strings.Mid(s, pos, attr.Length)
   f.SetValue(newValue, value)
   pos += attr.Length
  End If
 Next
 Return DirectCast(newValue, T)
End Function

などとしておいた方が良さそうです。

元のコードだと、
 'StructureFromString(Of BBB)("z").xxx.Length
 StructureFromText(Of BBB)("z").xxx.Length
が 0 になってしまいますが、この修正版であれば 2 が返されます。
引用返信 編集キー/
■65035 / inTopicNo.42)  Re[30]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ コンバート後に悩む人 (20回)-(2013/01/30(Wed) 13:50:41)
No65034 (魔界の仮面弁士 さん) に返信
> Substring だと、データ長を超える位置を指定したときに例外を発するため、
> 意図的に Strings.Mid を使っていました。

そのことすっかり失念してました。
これをベースに検討している大元のソースについて、
留意しつつコーディングすることとします。


> 元のコードだと、
>  'StructureFromString(Of BBB)("z").xxx.Length
>  StructureFromText(Of BBB)("z").xxx.Length
> が 0 になってしまいますが、この修正版であれば 2 が返されます。

これの意味は、"z"を代入したときのxxxの文字列の長さが2という意味でしょうか?
VB6.0までにはない記述法で、またまた勉強不足感がありました。


#魔界の仮面弁士さんを頼ってよかったです。2005年あたりにも構造体の質問の回答してましたから頼っちゃいました。

引用返信 編集キー/
■65036 / inTopicNo.43)  Re[31]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ 魔界の仮面弁士 (144回)-(2013/01/30(Wed) 14:26:58)
2013/01/30(Wed) 14:28:11 編集(投稿者)

No65035 (コンバート後に悩む人 さん) に返信
>>元のコードだと、
>> 'StructureFromString(Of BBB)("z").xxx.Length
>> StructureFromText(Of BBB)("z").xxx.Length
>>が 0 になってしまいますが、この修正版であれば 2 が返されます。
> これの意味は、"z"を代入したときのxxxの文字列の長さが2という意味でしょうか?

はい、そういうことです。上記を一度変数に受けるのであれば、
 Dim n As BBB = StructureFromText(Of BBB)("z")
 Console.WriteLine( n.xxx.Length )
のような感じですね。


> VB6.0までにはない記述法で、またまた勉強不足感がありました。
どの記述のことでしょうか?

ドットを連続して表記する書き方であれば、VB6 でも
 s = Form1.Text1.Text
 s = objADOConnection.Execute(SQL).Fields(0).Value
などとあるので、そう珍しくは無いですよね。

ということは、初見なのは「Of 」の事でしょうか?

だとすれば、これは「ジェネリック」という機能で、VB2005 から追加された機能です。
特に、List(Of ) クラスや Dictionary(Of ) クラスなどは出番の多い機能なので、
興味があれば調べてみてください。


> #魔界の仮面弁士さんを頼ってよかったです。2005年あたりにも構造体の質問の回答してましたから頼っちゃいました。
こちらとしても、召喚された甲斐がありました。

というのも、 No65012 などで用いた「FieldInfo の SetValue メソッド」は、今までは
構造体にセットする際には使えない(C# では使えるが、VB だと値がセットされない)という
問題があったので、Structure を Class に変更するなどして対処していたのですが、
今回の件でいろいろと試しているうちに、ValueType 型を経由させるという対処法を
偶然発見でき、回答側としても新たな発見がありました。ありがたや。
引用返信 編集キー/
■65038 / inTopicNo.44)  Re[32]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ コンバート後に悩む人 (21回)-(2013/01/30(Wed) 16:20:18)
2013/01/30(Wed) 16:25:00 編集(投稿者)
No65036 (魔界の仮面弁士 さん) に返信
> ということは、初見なのは「Of 」の事でしょうか?
> だとすれば、これは「ジェネリック」という機能で、VB2005 から追加された機能です。
> 特に、List(Of ) クラスや Dictionary(Of ) クラスなどは出番の多い機能なので、
> 興味があれば調べてみてください。

はい、そのとおりです。
この後大元の実装の際に、事前準備で調査してから着手しようと思います。

途中で変更、修正した個所も含めて、再度コードを展開して
今回の結びとさせていただきます。
魔界の仮面弁士さんありがとうございました。

複数の構造体から1つの構造体にコピー、または1つの構造体から複数の構造体にコピーする手法

手法@:shuさん作のコードNo65007
手法A:魔界の仮面弁士さん作の以下のコード


Imports System.Reflection
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices

Public Structure AAA
    <VBFixedString(2)> Public aaa As String
    <VBFixedString(3)> Public bbb As String
    <VBFixedString(5)> Public ccc As String
End Structure

Public Structure BBB
    <VBFixedString(3)> Public zzz As String
    <VBFixedString(5)> Public yyy As String
    <VBFixedString(2)> Public xxx As String
End Structure

Public Structure CCC
    <VBFixedString(2)> Public Field1 As String
    <VBFixedString(3)> Public Field2 As String
    <VBFixedString(5)> Public Field3 As String
    <VBFixedString(3)> Public Field4 As String
    <VBFixedString(5)> Public Field5 As String
    <VBFixedString(2)> Public Field6 As String
End Structure

Public Structure DDD
    <VBFixedString(1000)> Public Field As String
End Structure

Module Module1
    Sub Main()
        '文字列から構造体を作れます。
        Dim a1 As AAA = StructureFromString(Of AAA)("XXYYYZZZZZ")
        Console.WriteLine("=== AAA ===")
        Console.WriteLine("aaa=[" & a1.aaa & "]")
        Console.WriteLine("bbb=[" & a1.bbb & "]")
        Console.WriteLine("ccc=[" & a1.ccc & "]")

        '構造体メンバーを繋げて一つの文字列にできます。
        Dim strW As String = StructureToString(a1)
        Console.WriteLine("[" & strW & "]")

        '文字列を経由することで、別の構造体から取得することもできます。
        Dim b1 As BBB = StructureFromString(Of BBB)(StructureToString(a1))
        Console.WriteLine("zzz=[" & b1.zzz & "]")
        Console.WriteLine("yyy=[" & b1.yyy & "]")
        Console.WriteLine("xxx=[" & b1.xxx & "]")

        '文字列化して再代入すると、長さ調整ができます。
        Dim a2 As AAA
        a2.aaa = "Long Text"
        a2.bbb = "全+半"
        a2.ccc = "短い"
        Console.WriteLine("=== 長さ調整前 ===")
        Console.WriteLine("aaa=[" & a2.aaa & "]")
        Console.WriteLine("bbb=[" & a2.bbb & "]")
        Console.WriteLine("ccc=[" & a2.ccc & "]")
        Console.WriteLine("=== 長さ調整後 ===")
        a2 = StructureFromString(Of AAA)(StructureToString(a2))
        Console.WriteLine("aaa=[" & a2.aaa & "]")
        Console.WriteLine("bbb=[" & a2.bbb & "]")
        Console.WriteLine("ccc=[" & a2.ccc & "]")

        '複数の構造体を結合して、別の構造体に入れることも簡単にできます。
        Dim a3 As AAA
        a3.aaa = "Long Text"
        a3.bbb = "全+半"
        a3.ccc = "短い"
        Dim b3 As BBB = StructureFromString(Of BBB)("zzzYYYYYxx")
        Dim c3 As CCC = StructureFromString(Of CCC)(StructureToString(a3) & StructureToString(b3))
        Console.WriteLine("=== CCC ===")
        Console.WriteLine("Field1=[" & c3.Field1 & "]")
        Console.WriteLine("Field2=[" & c3.Field2 & "]")
        Console.WriteLine("Field3=[" & c3.Field3 & "]")
        Console.WriteLine("Field4=[" & c3.Field4 & "]")
        Console.WriteLine("Field5=[" & c3.Field5 & "]")
        Console.WriteLine("Field6=[" & c3.Field6 & "]")


'構造体DDDに複数の構造体(AAA、BBB)の内容をコピーする。
        Dim d4 As DDD = StructureFromString(Of DDD)(StructureToString(a3) & StructureToString(b3))

        Console.WriteLine("=== DDD ===")
        Console.WriteLine("Field=[" & d4.Field & "]")

        strW = StructureToString(d4)

'複数の構造体(AAA、BBB)に、構造体DDDの内容をコピーする。
        '開始位置を指定を渡さないStructureFromString
        Dim strW1 As String = Mid(strW, 1)
        Dim a5 As AAA = StructureFromString(Of AAA)(strW1)
        Dim strW2 As String = Mid(strW, Len(a5) + 1)
        Dim b5 As BBB = StructureFromString(Of BBB)(strW2)

        '開始位置を指定を渡すStructureFromString
        Dim a6 As AAA = StructureFromString(Of AAA)(strW)
        Dim b6 As BBB = StructureFromString(Of BBB)(strW, Len(a5))

    End Sub

    'VBFixedString 属性の付いたフィールドを連結し、その文字列を返します。
    Public Function StructureToString(Of T As Structure)(ByVal Stx As T) As String
        Dim sb As New StringBuilder()
        For Each f As FieldInfo In GetType(T).GetFields()
            Dim o() As Object = f.GetCustomAttributes(GetType(VBFixedStringAttribute), False)
            If o.Length <> 0 Then
                Dim attr As VBFixedStringAttribute = DirectCast(o(0), VBFixedStringAttribute)
                Dim strW As String
                strW = Strings.Left(CStr(f.GetValue(Stx)) & StrDup(attr.Length, " "c), attr.Length)
                sb.Append(strW)
            End If
        Next
        Return sb.ToString()
    End Function

    Public Function StructureFromString(Of T As Structure)(ByVal str As String) As T
        Dim newValue As ValueType = StructureFromString
        str &= StrDup(Len(newValue), " "c)
        Dim pos As Integer = 1
        For Each f As FieldInfo In newValue.GetType().GetFields()
            Dim attributes() As Object = f.GetCustomAttributes(GetType(VBFixedStringAttribute), False)
            If attributes.Length <> 0 Then
                Dim attr As VBFixedStringAttribute = DirectCast(attributes(0), VBFixedStringAttribute)
                Dim value As String = Strings.Mid(str, pos, attr.Length)
                f.SetValue(newValue, value)
                pos += attr.Length
            End If
        Next
        Return DirectCast(newValue, T)
    End Function

    Public Function StructureFromString(Of T As Structure)(ByVal str As String, ByVal intStart As Integer) As T
        Dim newValue As ValueType = StructureFromString
        str &= StrDup(Len(newValue), " "c)
        Dim pos As Integer = 1
        For Each f As FieldInfo In newValue.GetType().GetFields()
            Dim attributes() As Object = f.GetCustomAttributes(GetType(VBFixedStringAttribute), False)
            If attributes.Length <> 0 Then
                Dim attr As VBFixedStringAttribute = DirectCast(attributes(0), VBFixedStringAttribute)
                Dim value As String = Strings.Mid(str, intStart + pos, attr.Length)
                f.SetValue(newValue, value)
                pos += attr.Length
            End If
        Next
        Return DirectCast(newValue, T)
    End Function

End Module

解決済み
引用返信 編集キー/
■65042 / inTopicNo.45)  Re[26]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ コンバート後に悩む人 (22回)-(2013/01/31(Thu) 09:46:55)
No65027 (魔界の仮面弁士 さん) に返信
> 以下、No64971 の VB6 コードからの発展です。
> Let ステートメントの行によって、不足桁の内容が異なることに注意してください。

VB6.0のほうでも確認し、また元となるコードのほうも確認したところ
予め、Space関数で大きい構造体(この例ではStrB)をスペースで初期化していました。
従って、提示していただいた例題のコードでは
>  Let BBBB.strB = ""
と同じではありますが、Space関数をそのまま使用することとして
VB.net版のコードでも「" "c」でスペース埋めしている部分を
すべてSpace関数を使用することとしました。


#別な掲示板で「VB.netにて、構造体の中身をString変数にコピーするには?」という題目の件も
今回のこの手法でできそうですよね。


引用返信 編集キー/
■65047 / inTopicNo.46)  Re[27]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ shu (162回)-(2013/01/31(Thu) 12:05:32)
No65042 (コンバート後に悩む人 さん) に返信
> VB.net版のコードでも「" "c」でスペース埋めしている部分を
> すべてSpace関数を使用することとしました。
Mid関数もそうだけどSpace関数はMicrosoft.VisualBasic名前空間の
ものでこれらは出来るだけ使用しない方がよいと個人的には思います。
互換の為に用意されたものでありMicrosoft.VisualBasic名前空間外の
Framework上に用意されている機能で処理が可能なものがほとんどです。
特に実現出来た機能をわざわざMicrosoft.VisualBasic名前空間の関数で
置き換えるのは必要ないと思います。
引用返信 編集キー/
■65055 / inTopicNo.47)  Re[28]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ コンバート後に悩む人 (23回)-(2013/01/31(Thu) 15:00:46)
2013/01/31(Thu) 15:08:26 編集(投稿者)

No65047 (shu さん) に返信
>Mid関数もそうだけどSpace関数はMicrosoft.VisualBasic名前空間の
>ものでこれらは出来るだけ使用しない方がよいと個人的には思います。
>互換の為に用意されたものでありMicrosoft.VisualBasic名前空間外の
>Framework上に用意されている機能で処理が可能なものがほとんどです。
>特に実現出来た機能をわざわざMicrosoft.VisualBasic名前空間の関数で
>置き換えるのは必要ないと思います。

なるほど。確かにそのとおりですね。
となると、魔界の仮面弁士さんの提示いただいたコードだと
Microsoft.VisualBasic名前空間の関数を使用していますが
やはりこれはこれで提示いただいた例として、VB6.0のコードを徐々に無くす意味でも
VB2005で提供されている関数に置き換えてコーディングしたほうがより良いという感じですよね。
元コードの作業に入るときには、そのあたりも検討しつつですね。

環境的にはWin7なので、VB6.0のランタイムも配布済みの状態ですよね。
その上で、フレックスグリッドのOCXもランタイムに含まれているため
そのまま使用するつもりでいましたが、上述のとおりフレックスグリッドから
データグリッドに置き換えて考えるべきなのが正しい道ですよね。
ただ、そうなると全く別物なので、コスト面のことも考慮しつつとなりそうですが
修正量を鑑み、今のところはフレックスグリッドもそのまま使用という方向です。

引用返信 編集キー/
■65057 / inTopicNo.48)  Re[28]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ 魔界の仮面弁士 (145回)-(2013/01/31(Thu) 15:36:33)
# 雑談モード。

No65047 (shu さん) に返信
> Mid関数もそうだけどSpace関数はMicrosoft.VisualBasic名前空間の
> ものでこれらは出来るだけ使用しない方がよいと個人的には思います。

自分は、必ずしもそうとは思いません。

Microsoft.VisualBasic.Compatibility.VB6 名前空間のものであれば
利用を避けるべきでありと思っていますが、標準的に使われている
Microsoft.VisualBasic.CompilerServices 名前空間であるとか
Microsoft.VisualBasic 名前空間の物に関しては、私は特に
否定する理由を持ち合わせていません。
(この名前空間を否定してしまうと、ChrW や StrConv すら使えなくなります)


Substring の動作を望むなら、Substring を使えばよいでしょうし、
Left の動作を望むなら、Left を使えばよいのでは無いでしょうか。

自分が旧言語(BASIC や VB)に慣れているせいで、
そう感じるだけなのかも知れませんけれどね…。(^^;
C 系言語に慣れていたら、また逆の見方をしていたかも知れません。


> 特に実現出来た機能をわざわざMicrosoft.VisualBasic名前空間の関数で
> 置き換えるのは必要ないと思います。

そもそも完全に不要と判断されるものであれば、廃止の方向に動くか、
あるいは Microsoft.VisualBasic.Compatibility 系に追いやられるでしょうから、
そうでない物に関しては、使うかどうかは自己判断/現場判断で良いと思います。


ChrW は使わず、Convert.ToChar を使って開発することはできます。
Left を使わず、String.Substring を使って開発することもできます。
CreateObject の代わりに Activator.CreateInstance を使うことも、
MsgBox の代わりに MessageBox.Show を使うこともできます。


ただし、その置き換えが容易なものもあれば、標準機能での置き換えには
手間がかかりすぎる物もあります。なので名前空間そのものを否定的に見るのではなく、
個々の関数それぞれに対して、部分的に使い分けていくという考え方もあります。

実際、shu さんが論じているのは、必ずしも名前空間そのものでは無いですよね。
(「ほとんど」とは書いておられますが、「すべて」と論じているわけでは無い)
引用返信 編集キー/
■65060 / inTopicNo.49)  Re[29]: 【VB2005、VB.NET】構造体のコピーについて
□投稿者/ shu (164回)-(2013/01/31(Thu) 16:56:25)
No65057 (魔界の仮面弁士 さん) に返信
> # 雑談モード。
>
> ■No65047 (shu さん) に返信
>>Mid関数もそうだけどSpace関数はMicrosoft.VisualBasic名前空間の
>>ものでこれらは出来るだけ使用しない方がよいと個人的には思います。
>
> 自分は、必ずしもそうとは思いません。
もちろん他人に強制する内容ではありません。


> Microsoft.VisualBasic.Compatibility.VB6 名前空間のものであれば
> 利用を避けるべきでありと思っていますが、標準的に使われている
> Microsoft.VisualBasic.CompilerServices 名前空間であるとか
> Microsoft.VisualBasic 名前空間の物に関しては、私は特に
> 否定する理由を持ち合わせていません。
> (この名前空間を否定してしまうと、ChrW や StrConv すら使えなくなります)
身近なとこではChrWはほとんど使う場面はありませんがStrConvは使う場面がありますが
代わりとなるものがないと思われるので使用しています。ただ直接使用を避けラッピング関数を
用意するようにしています。


>
> Substring の動作を望むなら、Substring を使えばよいでしょうし、
> Left の動作を望むなら、Left を使えばよいのでは無いでしょうか。
LeftはUIクラス内でのLeftプロパティとかぶるので使用を避けています。


> そもそも完全に不要と判断されるものであれば、廃止の方向に動くか、
> あるいは Microsoft.VisualBasic.Compatibility 系に追いやられるでしょうから、
> そうでない物に関しては、使うかどうかは自己判断/現場判断で良いと思います。
これはそういう判断で良いと思います。


> 実際、shu さんが論じているのは、必ずしも名前空間そのものでは無いですよね。
> (「ほとんど」とは書いておられますが、「すべて」と論じているわけでは無い)
すべてではないです。ただ最近ではプロジェクトレベルでのインポートされた名前空間には
含めないようにし、ソースレベルでのImportsまたは直接名前空間の記述をするようにしています。
VisualBasicの関数を使用しているのであって他言語では一般的ではないことを分かりやすくして
おいた方が他言語メインの方が独自関数を作っているのではないことがそれで分かりやすくなると思います。
引用返信 編集キー/

<前の20件
トピック内ページ移動 / << 0 | 1 | 2 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -