VB.NET学習中に構造体とクラスライブラリの違いによるエラーに遭遇しました
- VB.NET学習58日目の初学者が、構造体の演習中にエラーに遭遇しました。具体的には、クラスライブラリと構造体の違いにより、Nullエラーが回避できませんでした。
- 質問者は、VB.NETのBLoad関数を作成し、クラスライブラリと構造体の両方で使用していましたが、構造体では問題なく動作しましたが、クラスライブラリではNullエラーが発生しました。
- このエラーについて教えてほしいとのことです。また、構造体とクラスライブラリの違いについても教えてほしいとのことです。
- ベストアンサー
クラス
VB.NET 学習58日目という初学者です。 未だ、Sub Main() でシコシコと基本事項の確認中です。 やっと構造体の演習を昨日から。 案の定、わからないことに遭遇しました。 ' ============================== ' TEST1、TEST2 の BSave、BLoad ' ============================== Module theTEST1 Sub Main() ' ----------------------- ' TEST1 の BSave、BLoad ' ----------------------- Dim T1 As New TEST1 T1.Member1 = "T1.Member1" T1.Member2 = "T1.Member2" BSave(T1, "D:\Temp\T1.BIN") T1.Member1 = "AAA" T1.Member2 = "BBB" Debug.Print(T1.Member1) Debug.Print(T1.Member2) T1 = CType(BLoad("D:\Temp\T3.BIN"), TEST1) If T1.Member1 <> Nothing Then ' Null エラーが回避できない! Debug.Print(T1.Member1) Debug.Print(T1.Member2) Else Message("") End If ' ----------------------- ' TEST2 の BSave、BLoad ' ----------------------- Dim T2 As TEST2 T2.Member1 = "T2.Member1" T2.Member2 = "T2.Member2" BSave(T2, "D:\Temp\T2.BIN") T2.Member1 = "AAA" T2.Member2 = "BBB" Debug.Print(T2.Member1) Debug.Print(T2.Member2) T2 = CType(BLoad("D:\Temp\T3.BIN"), TEST2) If T2.Member1 <> Nothing Then Debug.Print(T2.Member1) Debug.Print(T2.Member2) Else Message("") End If End Sub End Module Function BLoad(ByVal aPath As String) As Object If File.Exists(aPath) Then Try Using fs As New FileStream(aPath, FileMode.Open, FileAccess.Read) Dim bf As New BinaryFormatter Dim aObject As Object = bf.Deserialize(fs) fs.Close() Return aObject End Using Catch ex As IOException MsgBox(ex.Message & "(BLoad)", , "エラー:") Return Nothing End Try Else Return Nothing End If End Function T1 はクラスライブラリで定義。 T2 は構造体。 構造体の場合は、Nothing でチェックできました。 しかし、クラスライブラリの場合はチェックできません。 このエラーの考え方と処し方を教えてください。 構造体とクラスライブラリは表向きは同じようなもの。 ですから、どちらにも通用する BSave、BLoad 関数を作成使用としたわけです。 宜しくお願いします。
- Visual Basic
- 回答数1
- ありがとう数1
- みんなの回答 (1)
- 専門家の回答
質問者が選んだベストアンサー
T1などTEST1クラスのオブジェクトが Nothingかどうかを判別しましょう ' T1 = CType(BLoad("D:\Temp\T3.BIN"), TEST1) T1 = BLoad("D:\Temp\T3.BIN") ' でいいと思いますよ ' TEST1以外をデシリアライズしてきた場合は ' 代入のエラーになるので Try/Catchで対応かと If T1 IsNot Nothing Then ' Null エラーが回避できない! Debug.Print(T1.Member1) # 2003以前なら If not (T1 Is Nothing) Then ' Null エラーが回避できない! といった具合です BLoadやBSaveを TEST1クラスの Sharedメソッドとして実装したほうがいいかもしれませんよ
関連するQ&A
- VB.Net: クラスの共有メソッドの作り方?
あと3日でVB.Net学習2ヶ月目という初学者です。 Sub Main() のみで基本事項の確認のみをしてきました。 ですから、フォーム、レポート、データベース、WEB関連の知識は完全にゼロ。 さて、その基本演習も最終段階に突入。 いよいよクラスです。 ' ============================== ' クラスプログラミング; 演習3 ' ============================== Module theClass Sub Main() Dim T1 As New TEST1 T1.Member1 = "T1.Member1" T1.Member2 = "T1.Member2" T1.BSave("D:\Temp\T1.bin", DirectCast(T1, Object)) <--- ?1 T1.Member1 = "AAA" T1.Member2 = "BBB" Debug.Print(T1.Member1) Debug.Print(T1.Member2) T1.BLoad("D:\Temp\T1.bin", T1) <--- ?2 If T1 IsNot Nothing Then Debug.Print(T1.Member1) Debug.Print(T1.Member2) Else Message("T1.bin は読み込めませんでした。") End If End Sub End Module ?1=インスタンスを経由する共有メンバ、・・・へのアクセスです。正規の式は評価されません。 ?2=Option strict on では、'ByRef' パラメータのオブジェクトの値を・・・縮小変換できませんでした。 Public Shared Sub BSave(ByVal aPath As String, ByVal aObject As Object) Try Using fs As New FileStream(aPath, FileMode.Create, FileAccess.Write) Dim bf As New BinaryFormatter bf.Serialize(fs, aObject) fs.Close() End Using Catch ex As IOException MsgBox(ex.Message & "(BSave)", MsgBoxStyle.Exclamation, "エラー:") End Try End Sub Public Sub BLoad(ByVal aPath As String, ByRef aObject As Object) If File.Exists(aPath) Then Try Using fs As New FileStream(aPath, FileMode.Open, FileAccess.Read) Dim bf As New BinaryFormatter aObject = bf.Deserialize(fs) fs.Close() End Using Catch ex As IOException MsgBox(ex.Message & "(BLoad)", MsgBoxStyle.Exclamation, "エラー:") End Try End If End Sub 非共有の BSaveメソッドとBLoadメソッドのパラメータはファイルパスだけ。 共有メソッドの場合は、「何を」というのが必要かと思って2つ目のパラメータを追加。 もって、構造体の BSave と BLoad とに援用するテストをしたいと思っています。 し、しかし、上述の2つのエラーを前にどうしてよいか皆目わかりません。 >そのエラーを回避、もしくは発生させないためには次のように改造したらよい! そういう回答等をお願いします。
- ベストアンサー
- Visual Basic
- VB2008: 構造体に関するMSDNの解釈について!
' ================== ' 構造体変数の代入 ' ================== Module theTEST Private Structure TEST4 Dim MembersCount As Integer Dim Member1 As String Dim Member2 As String End Structure Sub Main() Dim T4_1 As TEST4 Dim T4_2 As TEST4 T4_1.MembersCount = 1 T4_1.Member1 = "T4_1:Member1" T4_1.Member2 = "T4_1:Member2" T4_2 = T4_1 Debug.Print(T4_2.MembersCount.ToString) Debug.Print(T4_2.Member1) Debug.Print(T4_2.Member2) End Sub End Module [イミディエイト ウインドウ] 1 T4_1:Member1 T4_1:Member2 >構造体の要素が文字列型 (String) やオブジェクト型 (Object) などの参照型である場合は、データへのポインタがコピーされます。 (http://msdn.microsoft.com/ja-jp/library/18ytyskd(VS.80).aspx) このMSDNライブラリの説明によると、 [イミディエイト ウインドウ] 0 T4_1:Member1 T4_1:Member2 という結果を得るというのが私の予測。 もしかしたら、MSDNライブラリの説明の舌足らず。 >構造体の要素が値型であらば値がコピーされますが、文字列型 (String) やオブジェクト型 (Object) などの参照型である場合は、データへのポインタがコピーされます。 ということでしょうか?
- ベストアンサー
- Visual Basic
- エクセルvba 検索対象をシートではなく、ブック全
このコードでシート内に検索文字があるかどうかを取得できるのですが 検索対象をシートではなく、ブック全体にするには どうすればいいでしょうか? Sub Sample() If Not Cells.Find(What:="test", LookAt:=xlPart) Is Nothing Then Debug.Print "あります" Else Debug.Print "ありません" End If End Sub
- ベストアンサー
- オフィス系ソフト
- 変数を続けて宣言した場合はEmpty型になる?
Sub test1() Dim Int1, Int2 As Long Debug.Print "---------- test1の実行結果 ----------" Debug.Print TypeName(Int1) Debug.Print TypeName(Int2) End Sub Sub test2() Dim Int1 As Long Dim Int2 As Long Debug.Print "---------- test2の実行結果 ----------" Debug.Print TypeName(Int1) Debug.Print TypeName(Int2) End Sub を実行すると、 ---------- test1の実行結果 ---------- Empty Long ---------- test2の実行結果 ---------- Long Long の結果が得られます。 test1のInt1がEmpty型になりますが、変数の型にEmptyはないですよね? どういうことなのでしょう???
- ベストアンサー
- オフィス系ソフト
- VBAで2つのプロシージャーをつなげるには
VBAでSub ~ End Subまで書き終えて、一つのプロシジャーを完成させたあと、 その下に、もう一つのプロシジャーを作り、連続してマクロを動かしたいと思ってます。 例に例えると、 Sub test() Dim MyRange As Range Set MyRange = Columns("c").Find(What:="﨑") If MyRange Is Nothing Then Debug.Print "環境依存文字ははみつかりません" Else MyRange.Font.ColorIndex = 3 End If Dim MyCells As Range Set MyCells = Columns("c").Find(What:="髙") If MyCells Is Nothing Then Debug.Print "環境依存文字ははみつかりません" Else MyCells.Font.ColorIndex = 3 End If End Sub Sub sample() Dim i As Long For i = 1 To Cells(Rows.Count, "I").End(xlUp).Row If InStr(1, Cells(i, "I"), "VBA", vbTextCompare) > 0 Then Cells(i, "M") = "YES" End If Next End Sub 上記のような2つのマクロをつなげて1つの実家行えるようにするにはどうしたらよろしいのでしょうか。 どうしても実行時に上のマクロと下のマクロが別々に表示されてしまします。 (ちなみに、上側のマクロは環境依存文字を探すマクロ、下側はVBAの文字を見つけ出すマクロです。) どなたかご存知の方いらっしゃいましたら、教えて頂けないでしょうか。 よろしくお願い致します。
- ベストアンサー
- その他(インターネット・Webサービス)
- VB2008: 独自例外とは?
独自例外の確認ための質問をします。 独自例外の発生をキャッチして表示する術がわからなくて苦肉の策でエラートラップを利用。 しかし、こういう事であれば何も独自例外を設定する必要がありません。 と思ったり、「スルーだからテストに<0除算>を選んだのが悪いのか?」と考えたり。 ともかく、判っているのか判っていないのかが判らない状態に陥っています。 そういうことで、独自例外について少し教えて頂ければ幸いです。 ' ============================== ' クラスプログラミング; 演習2 ' ============================== Module theClass Sub Main() On Error GoTo Error_Main Dim T1 As New TEST1 Debug.Print(T1.MembersLengthAverage.ToString) Exit_Main: Exit Sub Error_Main: ErrorMsg(Err.Description & "(Main)") Resume Exit_Main End Sub End Module ' ================================================================== ' クラス TEST1 ' ================================================================== <Serializable()> Public Class TEST1 Private _MemberCount As Integer Private _Member1 As String Private _Member2 As String ReadOnly Property MembersLengthAverage() As Integer Get If _MemberCount <> 0 Then Return (_Member1.Length + _Member2.Length) \ _MemberCount Else Throw New System.Exception("TEST1: 除算エラーが発生しました。" ) End If End Get End Property Public Sub New() _Member1 = "" _Member2 = "" End Sub End Class
- ベストアンサー
- Visual Basic
- VB2008: クラスライブラリとはなんなのか?
クラスライブラリとはなんなのか? 私は、クラスライブラリとはプロパティやメソッドを備えたもの。 そういう理解をしていました。 しかし、今、その認識が揺らいでいます。 それは、System.Text との出会いがきっかけ。 Imports System.IO Module mdlFileSystem Function FileSeek(ByVal aFile As String, _ ・・・・・ If File.Exists(aFile) Then Dim Buf(1) As Byte Dim ec As System.Text.Encoding = System.Text.Encoding.Default Dim fs As FileStream = New FileStream(・・・・・) これは、次のようにも書けます。 Imports System.IO Imports System.Text Module mdlFileSystem Function FileSeek(・・・・・) As String ・・・・・ If File.Exists(aFileName) Then Dim Buf(1) As Byte Dim ec As Encoding = Encoding.Default Dim fs As FileStream = New FileStream(・・・・・) この New 宣言を必要としない関数群とも言えるクラスライブラリ。 ここで、何が問題かと言うと実は自作の LenB関数の扱い。 Public Class Text #Region "LenB メソッド" ・・・・・ #End Region #Region "LenB メソッド" ・・・・・ #End Region End Class このように書くこともできます。 別にクラスライブラリなどと上段に構えなくても標準ライブラリでも用は足ります。 言わば、複数のプロパティやメソッドを装備しないのだ単なる標準ライブラリのクラスライブラリ版。 本格的なクラスライブラリ、標準ライブラリのクラスライブラリ版、標準ライブラリ。 一体、この3つをどう切り分けすべきなのであろうか? VB2008を学び始めて3週間。 しかも、プログラマでもなんでもない素人。 この辺りをどのように考えたらいいのでしょうか? どうにもスッキリしません。 「このように考えたらいいですよ」という回答をお願いします。
- ベストアンサー
- Visual Basic
- VB2008: ファイルから1行づつ読み込む関数のバグの修正方法?
' ========================================== ' 全ての行を読み込んで "" 行以外を出力する ' ========================================== Module theGrap Sub Main() Dim iNow As Integer = 0 Dim iNext As Integer = 0 Dim aLine As String = "" Do iNow = iNext aLine = FGets("D:\Temp\Test4.txt", iNow, iNext) If aLine = "" Then Continue Do Debug.Print(aLine) Loop Until iNext = -1 End Sub End Module [イミディエイト ウインドウ] 123あいうえお90 123かきくけこ90 123さしすせそ90 と、成功しています。 ' -------------- ' 行末まで読む ' -------------- Do fs.Seek(iNowPosition, SeekOrigin.Begin) fs.Read(aBuf, 0, 2) aChar = ec.GetString(aBuf).Substring(0, 1) If aChar <> Chr(13) Then aChars &= aChar Else iNowPosition = iNowPosition - 1 Exit Do End If iNowPosition += txt.LenB(aChar) Loop While iNowPosition < fs.Length And (aChar <> Chr(13) Or aChar <> Chr(10)) しかし、実は、FGets 関数では1文字づつ読み込んでいます。 そこで、StreamReader で一行を読み込むように修正。 [イミディエイト ウインドウ] 123?????90 123?????90 123?????90 すると見事に化けてしまいました。 化けること自体は理解できるのですが、化けを修正する術がわかりません。 Function FGetl(ByVal aFile As String, _ ByVal iNowPosition As Integer, _ ByRef iNextPosition As Integer) As String Dim aBuf(1) As Byte Dim aChars As String = "" iNextPosition = -1 If File.Exists(aFile) Then Try Using fs As FileStream = New FileStream(aFile, FileMode.Open, FileAccess.Read) Dim sr As StreamReader Dim ec As Encoding = Encoding.Default fs.Seek(iNowPosition, SeekOrigin.Begin) sr = New StreamReader(fs) aChars = sr.ReadLine iNowPosition += txt.LenB(aChars) iNextPosition = NextPosition(fs, iNowPosition) fs.Close() Return aChars End Using Catch ex As IOException MsgBox(ex.Message & "(FGets)", MsgBoxStyle.Exclamation, "エラー:") Return "" End Try Else Return "" End If End Function 文字の化けを修正する方法を教えて頂ければ幸いです。
- ベストアンサー
- Visual Basic
- リンク元のパスを変更したい vba アクセス
アクセスです。 該当する複数のテーブルの、リンク元のパスを変更したいのですが Sub Sample() Dim DB As Database Dim T As TableDef Dim mystr As String Set DB = OpenDatabase(CurrentProject.FullName) For Each T In DB.TableDefs mystr = CurrentDb.TableDefs(T.Name).Connect If mystr Like "*\\該当のパス*" Then Debug.Print T.Name Debug.Print CurrentDb.TableDefs(T.Name).Connect ’自分としてはこれで変更できると思った CurrentDb.TableDefs(T.Name).Connect = _ ";DATABASE=C:\新たなパス\○○.accdb" Debug.Print CurrentDb.TableDefs(T.Name).Connect End If Next DB.Close Set DB = Nothing End Sub を実行してもエラーにもならないし、リンクテーブルのパスも変わりません。 CurrentDb.TableDefs(T.Name).Connect はパスの取得しかできないのでしょうか? パスを設定する方法を教えてください。 よろしくお願いします。
- ベストアンサー
- オフィス系ソフト
- VBA null判定
Accessでテキストボックスの値をテーブルへ書き込むVBAを作成しているのですが、Null判定がうまくいきません。 ◎環境 OS:Windows7Pro Var:Access2010 DB:MySQL5.6 Private Sub cmdSubmit_Click() Dim Rst As DAO.Recordset Dim ErrT As String Set Rst = CurrentDb.OpenRecordset("m_plan", dbOpenDynaset) '各テキストボックス、Null判定 If IsNull(txtPid) Then MsgBox "プランID[" & txtPid & "]が未入力です" Call txtCrer Exit Sub End If If IsNull(txtPName) Then MsgBox "プラン名が未入力です" Call txtCrer Exit Sub End If If IsNull(txtPsdate) Then Me!txtPsdate = #01/01/2010# End If If IsNull(Me!txtPedate) Then Me!txtPedate = #01/01/2010# End If Debug.Print "プランID["; Me.txtPid & "]" Debug.Print "プラン名[" & Me!txtPName & "]" Debug.Print "開始日[" & Me!txtPsdate & "]" Debug.Print "終了日[" & Me!txtPedate & "]" ↑↑↑↑↑↑↑↑↑ ここで、Null判定を行ってますが、データがあるにも関わらず、処理が続行されたり、Null判定結果が起動するたびに変わります。 On Error GoTo err With Rst .MoveLast .AddNew .Fields("PlanID") = Me!txtPid .Fields("PlanName") = Me!txtPName .Fields("PlanSt") = CDate(Me!txtPsdate) .Fields("PlanEn") = CDate(Me!txtPedate) .Fields("P_Remaks") = Me!txtPbikou .Update End With Rst.Close Set Rst = Nothing err: MsgBox "DBエラー" Debug.Print Rst.Type Debug.Print err.Description Call txtCrer End Sub ただし、下記判定だけのボタンとプロシージャーでは、正常に判定されます。 判定だけの、プロシージャー 'Null判定テスト Private Sub cmdtest_Click() If IsNull(txtPid) Then Debug.Print "[" & txtPid & "]" & "Nullです。" Else Debug.Print "[" & txtPid & "]" & "Not Nullです。" End If If IsNull(txtPName) Then Debug.Print "[" & txtPName & "]" & "Nullです。" Else Debug.Print "[" & txtPName & "]" & "Not Nullです。" End If If IsNull(txtPsdate) Then Debug.Print "[" & txtPsdate & "]" & "Nullです。" Else Debug.Print "[" & txtPsdate & "]" & "Not Nullです。" End If Debug.Print "===============================" End Sub どこが間違っているかまったくわかりません、アドバイスを頂けましたら幸いです。
- ベストアンサー
- その他(データベース)
お礼
侍ジャパンを見ながら BLOAD、BSAVE を作成。 「NULL だから ISNOT NULL の要領かなー?」と思いましたが・・・。 結局は、悉く失敗。 回答の如くで成功しました。 >BLoadやBSaveを TEST1クラスの Sharedメソッドとして実装したほうがいいかもしれませんよ! クラスライブラリは12、3年前に一度だけ作ったことがあるだけ。 で、構造体=>ファイルアクセス=>クラスライブラリと攻める予定です。 が、構造体とクラスとが余りにも表向きが一緒なものでチト踏み込んだ次第です。 アドバイスの<Sharedメソッドとして実装>の意味は皆目わかりませんが是非に挑戦したいと思います。