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

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

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

Re[7]: Integer配列とArrayの代入


(過去ログ 110 を表示中)

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

■65132 / inTopicNo.1)  Integer配列とArrayの代入
  
□投稿者/ MassyPie (11回)-(2013/02/07(Thu) 11:15:21)

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

今回もよろしくお願い致します。

VB6−>2010への変換をしています。

今までLongの配列だった変数が、Integerの配列やArrayに自動変換されました。
変換後のプログラムを見ると、次のような2ケースがありました。

ケース1.
<呼び元>

Dim intInt() as Integer
.
.
.


OPCA(intInt)


<呼び先>
Array(ByRef System.Array)



ケース2.
<呼び元>

Dim arryInt as System.Array
.
.
.


OPCA(arryInt)


<呼び先>
Int(intInt() as Integer)


このままでは変数の型が合わないので、Int()をArrayに入れたり、ArrayをInt()に入れたりして、次のように呼ぶ前に違う変数に値を入れ直しています。
しかし、型を同じにしても正常に動くものもあれば、動かないものもあります。動かないモジュールは、全て次のエラーが出ます。


エラーNO.:5
エラー内容:値が有効な範囲にありません。


ここからが、質問です。


Q1.
このような方法での型変換で良いのでしょうか?


Q2.
他のもっと簡単で、エラーが出ない型変換の方法(例えば型変換の関数があるなど)がありましたら、ご教授したくよろしくお願い致します。


尚、呼び先はDLL化されており、修正は行えません。


Dim A_Int as System.Array
Dim intInt() as Integer
.
.
.

'*** Array -> Int()
A_Int = intInt



'*** Int() -> Array
ReDim Preserve intInt(A_Int.Length - 1)
For i = Lbound(intInt) to Ubound(intInt)
intInt(i) = A_Int(i + 1)
Next i






引用返信 編集キー/
■65133 / inTopicNo.2)  Re[1]: Integer配列とArrayの代入
□投稿者/ shu (170回)-(2013/02/07(Thu) 11:27:04)
No65132 (MassyPie さん) に返信

元コードと変換コードでの比較を書いた方がよいと思います。

ある型の配列はArrayの派生クラスのようなものと思ってください。
以下のコードはエラーなく動きます。変換後のコードはちゃんと型指定した配列を
使った方がよいと思います。
        Dim aa As Array
        Dim ai() As Integer

        aa = New Integer() {1, 2, 3}
        ai = CType(aa, Integer())
        aa = New String() {"a", "b", "c"}

引用返信 編集キー/
■65137 / inTopicNo.3)  Re[2]: Integer配列とArrayの代入
□投稿者/ MassyPie (12回)-(2013/02/07(Thu) 15:21:29)
shuさん、ありがとうございます。
動作を確認してみました。実際に現実に近い値を設定して確認しようと思ったのですが、疑問点が出てきました。
ご教授ください。


Q1.

> aa = New Integer() {1, 2, 3}

aaのArrayに、1, 2, 3 を入れています。
今回は、値を具体的に書いて入れるのではなく、integerの配列に入っている値を入れます。

Dim bi() As Integer = {75000000, 75000001, 75000002}

この bi を、aaに設定するにはどのように記述すれば良いのでしょうか?

イメージ的には、aa = New Integer() {bi} です。



Q2.

> 以下のコードはエラーなく動きます。変換後のコードはちゃんと型指定した配列を
> 使った方がよいと思います。

下記のような場合は、型指定をしていないということでしょうか?

ウオッチ・ウインドウで ba を見た時、型がIntegerになっているので、これは bi の値が設定された時に型も正式に型指定されたのか、テンポラリなのかという質問です。


Dim ba As Array
Dim bi() As Integer = {75000000, 75000001, 75000002}


'Array -> Int()
ba = bi


Q3.

実際のプログラムは長すぎるので、ここには貼り付けすることができないのですが、

ai = CType(aa, Integer())

相当を実行しました。実際の値は上に記述しているような、75000000といったような値です。

その行を実行後に、次のようなエラーが発生しました。

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
InvalidCastException はハンドルされませんでした。
型'System.Int32[*]'のオブジェクト型'System.Int32[]'にキャストできません。
元の型が目的型と互換性があることを確認します。
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

> aa = New Integer() {75000000, 75000001, 75000002}
> ai = CType(aa, Integer())

のように変更し、実行しましたが同様のエラーは発生しませんでした。
実際に近い値を入力しエラーが出ていないので、ai ではなく実は別の所が問題ではないか等、いろいろと疑っています。
考えられる現象がありましたら、よろしくお願い致します。
引用返信 編集キー/
■65139 / inTopicNo.4)  Re[3]: Integer配列とArrayの代入
□投稿者/ shu (171回)-(2013/02/07(Thu) 15:48:02)
No65137 (MassyPie さん) に返信
> この bi を、aaに設定するにはどのように記述すれば良いのでしょうか?
>
> イメージ的には、aa = New Integer() {bi} です。
>
これが違うので

> その行を実行後に、次のようなエラーが発生しました。
>
> −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
> InvalidCastException はハンドルされませんでした。
> 型'System.Int32[*]'のオブジェクト型'System.Int32[]'にキャストできません。
> 元の型が目的型と互換性があることを確認します。
> −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
このエラーが出ていると思います。

biをaaに設定するには
aa=biでよいです。

> Dim bi() As Integer = {75000000, 75000001, 75000002}
においてbi = new Integer() {75000000, 75000001, 75000002}
と同じです。
私の提示コード
と同じように書くと
aa= new Integer() {75000000, 75000001, 75000002}
となりこれは
aa=bi
と同じです。

エラーの内容は配列の要素がIntegerではないためIntegerの配列に
変換することが出来ませんという内容です。

引用返信 編集キー/
■65140 / inTopicNo.5)  Re[3]: Integer配列とArrayの代入
□投稿者/ shu (172回)-(2013/02/07(Thu) 16:00:32)
No65137 (MassyPie さん) に返信
> Q2.
>
>>以下のコードはエラーなく動きます。変換後のコードはちゃんと型指定した配列を
>>使った方がよいと思います。
>
> 下記のような場合は、型指定をしていないということでしょうか?
>
> ウオッチ・ウインドウで ba を見た時、型がIntegerになっているので、これは bi の値が設定された時に型も正式に型指定されたのか、テンポラリなのかという質問です。
>
>
> Dim ba As Array
> Dim bi() As Integer = {75000000, 75000001, 75000002}
>
>
> 'Array -> Int()
> ba = bi

先に書いたようにすべての型の配列はArrayの派生クラスのようなもの
であるので配列型はすべてArray型になります。逆はなりたたずArray型で
あってもIntegerの配列かStringの配列であるかその他の配列であるかは
定まりません。実際に設定されている配列の内容により変わります。
今回の場合Integer配列を設定しているので
ArrayからInteger配列に変換する場合キャストを行うことが可能なので
Ctype(〜,Integer())
とすることが可能になります。
引用返信 編集キー/
■65141 / inTopicNo.6)  Re[4]: Integer配列とArrayの代入
□投稿者/ 魔界の仮面弁士 (151回)-(2013/02/07(Thu) 16:07:06)
2013/02/07(Thu) 16:08:55 編集(投稿者)

No65139 (shu さん) に返信
> biをaaに設定するには
> aa=biでよいです。

元コードが VB6 とのことで、ByVal / ByRef を意識していない可能性も
ありえます。直接代入以外の処理が必要となることもあるかも。


たとえば、下記で a をコピー元とした時、コピー先に求めている動作が、
b なのか c/d なのかは、あらかじめ確認しておいた方が良いでしょう。
(ByRef 引数に渡す場合は b の動作、ByVal 引数に渡す場合は c の動作)

Dim a() As Integer = {111, 222, 333, 444}
Dim b() As Integer = a
Dim c() As Integer = a.ToArray()
Dim d() As Integer = DirectCast(a.Clone(), Integer())

a(0) = 555
b(1) = 666
c(2) = 777
d(3) = 888

' この時点では、このような状態になっている。
' a は、555, 666, 333, 444
' b は、555, 666, 333, 444
' c は、111, 222, 777, 444
' d は、111, 222, 333, 888
引用返信 編集キー/
■65143 / inTopicNo.7)  Re[4]: Integer配列とArrayの代入
□投稿者/ MassyPie (13回)-(2013/02/07(Thu) 16:42:31)
shuさん、ご丁寧なご回答をありがとうございます。
勉強になりました。


さて、実際のプログラムの宣言部分をコピーしました。


Friend Class Form1
Inherits System.Windows.Forms.Form
Private ServerHandles As System.Array
Private ServerErrors As System.Array

( 略 )


Private Sub Timer1_Tick(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Timer1.Tick

Dim R_ServerHandles() As Integer
Dim R_ServerErrors() As Integer

( 略 )

R_ServerHandles = CType(ServerHandles, Integer())
R_ServerErrors = CType(ServerErrors, Integer())

( 略 )

End Sub



ServerHandles は、ウオッチで見ると 

0番目:75702848
要素数:1
型:Integer です。

ServerHandles や R_ServerErrors にカーソルをあて、Shift + F2 を押しても、宣言している部分(上記の)に飛んでいきます。

エラーが出るのは、CType(ServerHandles, Integer()) のInteger変換がうまくいっていないのでしょうか?
引用返信 編集キー/
■65144 / inTopicNo.8)  Re[4]: Integer配列とArrayの代入
□投稿者/ MassyPie (14回)-(2013/02/07(Thu) 16:46:54)
魔界の仮面弁士さんのレス、失念しておりました。

これから、確認してみます。

ありがとうございます。
引用返信 編集キー/
■65145 / inTopicNo.9)  Re[5]: Integer配列とArrayの代入
□投稿者/ shu (173回)-(2013/02/07(Thu) 16:55:01)
No65141 (魔界の仮面弁士 さん) に返信
> 2013/02/07(Thu) 16:08:55 編集(投稿者)
フォローありがとうございます。
確かに配列をByValで渡すかByRefで渡すか
配列のコピーをするのかは考慮しなければならない点ですね。



No65143 (MassyPie さん) に返信
>
>
> ServerHandles は、ウオッチで見ると 
>
> 0番目:75702848
> 要素数:1
> 型:Integer です。
>
> ServerHandles や R_ServerErrors にカーソルをあて、Shift + F2 を押しても、宣言している部分(上記の)に飛んでいきます。
>
> エラーが出るのは、CType(ServerHandles, Integer()) のInteger変換がうまくいっていないのでしょうか?
ServerHandles が2重の配列になっていませんか?
ServerHandles(0)は75702848になっていますでしょうか?
Arrayのままにしておく意味はあるのでしょうか?

引用返信 編集キー/
■65148 / inTopicNo.10)  Re[6]: Integer配列とArrayの代入
□投稿者/ MassyPie (16回)-(2013/02/07(Thu) 17:56:09)

> 確かに配列をByValで渡すかByRefで渡すか
> 配列のコピーをするのかは考慮しなければならない点ですね。

最初の方法ではクールでないし、もっといい方法がと思い質問させて頂いたのですが、下記のByVal方式であると正常に動きます。
自分としては、あまり良い方法ではないと思っていましたが、確実を期すために下記の方法で行くことにします。


ReDim Preserve intInt(A_Int.Length - 1)
For i = Lbound(intInt) to Ubound(intInt)
intInt(i) = A_Int(i + 1)
Next i


−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
上記は、ArrayをInt()に設定する方法ですが、Int()をArrayにByVal方式で設定するには、どのような書き方をすればよいのでしょうか?
よろしくお願い致します。
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−




下記はウオッチウインドウで見た結果です。

> ServerHandles が2重の配列になっていませんか?
なっていません。

> ServerHandles(0)は75702848になっていますでしょうか?
なっています。

> Arrayのままにしておく意味はあるのでしょうか?
関数の引数が、Arrayだったり、Int()だったりしているので、関数を呼ぶ手前で型変換をする必要があります。
VB6では、Long()だったものが、Array、Int()と入り乱れているので、その度に型変換が必須です。

全体の作り直しも頭をよぎりましたが、ボリュームがあり、また私のようなレベルではまた別の問題が発生しかねないので、それは考えていません。
引用返信 編集キー/
■65155 / inTopicNo.11)  Re[7]: Integer配列とArrayの代入
□投稿者/ shu (174回)-(2013/02/08(Fri) 00:10:06)
No65148 (MassyPie さん) に返信
> −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
> 上記は、ArrayをInt()に設定する方法ですが、Int()をArrayにByVal方式で設定するには、どのような書き方をすればよいのでしょうか?
> よろしくお願い致します。
> −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

ArrayからInteger()へキャストすればいいだけです。


    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim a As Array = {1, 2, 3}
        Dim b() As Integer = {4, 5, 6}
        Console.WriteLine("a(0) = {0}", CType(a, Integer())(0))
        Console.WriteLine("b(0) = {0}", b(0))
        Console.WriteLine("Castでインスタンスは変わらない {0}", a Is CType(a, Integer()))
        ArraySet(a)
        Console.WriteLine("After ArraySet(a) a(0) = {0}", CType(a, Integer())(0))
        ArraySet(b)
        Console.WriteLine("After ArraySet(b) b(0) = {0}", b(0))
        IntArraySet(CType(a, Integer()))
        Console.WriteLine("After IntArraySet(a) a(0) = {0}", CType(a, Integer())(0))
        IntArraySet(b)
        Console.WriteLine("After IntArraySet(b) b(0) = {0}", b(0))
    End Sub

    Private Sub ArraySet(ByVal ary As Array)
        CType(ary, Integer())(0) = 11
    End Sub

    Private Sub IntArraySet(ByVal ary() As Integer)
        ary(0) = 14
    End Sub


MassyPie さんの
> intInt(i) = A_Int(i + 1)
A_int As Array
だとするとこれは遅延バインディングを利用しているのでコンパイルオプション
によってはエラーとなりますので気を付けて下さい。
遅延バインディングを使用しない書き方だと上記コードのように
intInt(i) = CType(A_int,Integer())(i + 1)
のように書く必要があります。
CTypeはDirectCastと書いても大丈夫です。その方がパフォーマンスはよくなります。

引用返信 編集キー/
■65197 / inTopicNo.12)  Re[8]: Integer配列とArrayの代入
□投稿者/ MassyPie (17回)-(2013/02/12(Tue) 15:19:15)
2013/02/12(Tue) 15:22:58 編集(投稿者)

shuさん

ご回答ありがとうございます。


> ArrayからInteger()へキャストすればいいだけです。

これは、shuさんのプログラムを実行し、確認しました。
よく分かりました。ありがとうございます。

そして、もう1つ質問です。

shuさんのプログラムで、a のサイズ(と、値)を設定しています。
実際プログラムでは、配列 b は関数の戻り値なので、サイズがいくつか分かりません。

---------------------------------------------------
配列でいうRedimは、Arrayではどのように設定すればよいのでしょうか?
---------------------------------------------------


調べたのですが、分からなかったので、下のテストプログラムでは、a = b と強制的にサイズを設定しました。


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim a As Array = Nothing
Dim b() As Integer = {4, 5, 6}
Dim intI As Integer

a = b 'Arrayのサイズの定義が分らない

For intI = LBound(b) To UBound(b)
MyArraySet(a, intI)
Next intI

End Sub

Private Sub MyArraySet(ByVal ary As Array, ByVal intVal As Integer)
CType(ary, Integer())(intVal) = intVal
End Sub



> intInt(i) = CType(A_int,Integer())(i + 1)
> のように書く必要があります。
> CTypeはDirectCastと書いても大丈夫です。その方がパフォーマンスはよくなります。

了承致しました。
これで書いてみます。


引用返信 編集キー/
■65199 / inTopicNo.13)  Re[9]: Integer配列とArrayの代入
□投稿者/ shu (181回)-(2013/02/12(Tue) 16:27:56)
No65197 (MassyPie さん) に返信
> ---------------------------------------------------
> 配列でいうRedimは、Arrayではどのように設定すればよいのでしょうか?
> ---------------------------------------------------
>
>
> 調べたのですが、分からなかったので、下のテストプログラムでは、a = b と強制的にサイズを設定しました。
>
>
・・・
>
> a = b 'Arrayのサイズの定義が分らない
Arrayに設定するのと配列に設定するのは変わりません。
Redimは以前のVBとの互換用に残っていますが
.Netでは
(1) new 要素型(サイズ) {}
(2) new 要素型() {要素1,要素2, ... , 要素n}
(3) Array.CreateInstance(GetType(要素型), サイズ)
で配列のインスタンスを作成できます。(3)は戻り値がArray型となります。
だからといってArrayに設定するのに(3)を使用しなければならないということではないです。

配列のサイズは1次元であればLengthを使うのがよいと思います。2次元以上の場合はGetLengthを
使うとよいです。
引用返信 編集キー/
■65202 / inTopicNo.14)  Re[5]: Integer配列とArrayの代入
□投稿者/ MassyPie (18回)-(2013/02/12(Tue) 17:36:38)
shuさん

ありがとうございます。
全て型を揃えることができました。

ただ、エラーは変わらず出ています・・・

エラーNO.:5
エラー内容:値が有効な範囲にありません。



最後に1つだけ質問です。

DLL化されている関数なので中身は見ることができませんが、Shft+F2でオブジェクトブラウザに飛び、引数の型を見ることができます。

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
XXXXX(Integer, ByRef System.Array, ByRef System.Array)
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

となっているため、Integer(VB6の時はLong)の配列に入っていたデータを、Integer型のArrayに入れ替えていました。
しかし、この引数を見るとArrayとは書いてありますが、Integerとはありません。


このArrayの型は、どのように確認できるのでしょうか?
また、確認できるようなものなのでしょうか?

どうぞよろしくお願い致します。
引用返信 編集キー/
■65207 / inTopicNo.15)  Re[6]: Integer配列とArrayの代入
□投稿者/ shu (182回)-(2013/02/13(Wed) 09:21:10)
No65202 (MassyPie さん) に返信
> −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
> XXXXX(Integer, ByRef System.Array, ByRef System.Array)
> −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
>
> となっているため、Integer(VB6の時はLong)の配列に入っていたデータを、Integer型のArrayに入れ替えていました。
> しかし、この引数を見るとArrayとは書いてありますが、Integerとはありません。
>
>
> このArrayの型は、どのように確認できるのでしょうか?
> また、確認できるようなものなのでしょうか?
DLL内で想定している型を知ることは出来ません。値が有効範囲内にないということは
Integerの範囲ではDLL側で処理出来ないということだと思うのでShortの範囲にしてみてはどうでしょう?
またはDLL側で渡した配列に値を設定するときに発生しているのであれば配列の型をLong配列にしてみるとか。
引用返信 編集キー/
■65209 / inTopicNo.16)  Re[7]: Integer配列とArrayの代入
□投稿者/ MassyPie (19回)-(2013/02/13(Wed) 10:27:58)
shuさん

ご回答ありがとうございます。

> DLL内で想定している型を知ることは出来ません。値が有効範囲内にないということは
> Integerの範囲ではDLL側で処理出来ないということだと思うのでShortの範囲にしてみてはどうでしょう?
> またはDLL側で渡した配列に値を設定するときに発生しているのであれば配列の型をLong配列にしてみるとか。

ここから先は、Try & Error ということですね。
それで進めて行ってみます。

本当にありがとうございました。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -