VB.NET 文法メモ

## 構文
#### **なんかいろいろ。**
```vb
'改行方法 … 「 _ 」、「(」や「=」のあと他。
'コメント … 先頭にシングルクオーテーション
'コロン … 複数行を一行にまとめる

test1 = 
"test1" : test2 =
"test2" 'コメント
```


#### **演算子(知らなかったもののみ)**

|記号|説明|記号|説明|
|---|---|---|---|
|￥|整数除算(商)|Mod|乗除演算(あまり)|￥|整数除算(商)|
|<>|等しくない|^|指数演算(^=)|
|x += 1|x = x + 1 (x++)|x -= 1|x = x - 1 (x--)|
|<<=<br>>>=||<<<br>>>||
|&|文字列連結|Xor|排他的論理和|
|AndAlso|左がFalseの場合は右は見ないAnd|OrELSE|左がFalseの場合は右は見ないOR|
|IS<br>IS NOT|同一のオブジェクトを参照しているか/否か|LIKE|右のパターンと一致するか|
|IsTrue||ISFalse||


#### **制限 – ファイルの先頭に記載することで制限をかける**
```vb
'暗黙の変数宣言
Option Explicit Off ' 変数宣言を必要としないようにする
Option Explicit On  ' 変数宣言が必ず必要になるようにする(デフォ)

'暗黙の型変換
Option Strict Off  ' 自動型変換ON(デフォ)
Option Strict On   ' 自動型変換OFF

'文字列の比較アルゴリズム設定
Option Compare Text   ' 文字列比較時に大文字小文字区別しない
Option Compare Binary ' 文字列比較時に大文字小文字区別する(デフォ)

'ローカル型の推論
Option Infer Off ' 型推論OFF
Option Infer On  ' 型推論ON(デフォ)
```
## 変数と定数
#### **宣言**

```vb

'変数宣言
Dim variable_name As data_type
Dim variable_name As data_type = default_value
Dim variable_name
Dim variable_name = default_value '※型推論
Dim variable_name1, variable_name2, variable_name3 As data_type
'定数宣言
Const variable_name As data_type
Const variable_name As data_type = default_value
Const variable_name
Const variable_name = default_value '※型推論
Const variable_name1, variable_name2, variable_name3 As data_type

```

## 配列
#### **宣言**
```vb
Dim list_name(index_max_value) As data_type
Dim list_name() As data_type = New data_type(index_max_value){
                                        default_value1, default_value2}
Dim list_name() As data_type = {default_value1, default_value2}
Dim list_name As New List(Of data_type)(New data_type() {default_value1, default_value2, default_value3})

'再定義(Preserve...既に格納されている値の保持)
ReDim [Preserve] Pre_list_name(new_index_max_value)
Pre_List_name(nex_index) = value ' 追加
```
#### **可変配列(要素はObject型として管理)**
```vb

' ArrayList ... object型
Dim list_name As New ArrayList ' 宣言
list_name.Add(value)           ' 追加
list_name.Insert(index, value) ' 挿入
list_name.Count                ' 要素数取得
list_name.Item(index)          ' 要素の取得
list_name.Contains(value)      ' 要素の検索(bool)
list_name.Remove(value)        ' 指定の(一番初めに出現した)要素を削除
list_name.RemoveAt(index)      ' 指定の場所の要素を削除
list_name.Clear()              ' すべての要素の削除
list_name.Sort()               ' ソート

' List(Of data_type) ... 型指定あり, 基本こっちを使おう
' 都度キャストが必要ないためarraylistよりパフォーマンスが上
Dim list_name As New List(Of data_type)() ' 宣言
' あとは大体上と同じ
```
#### **連想配列**
```vb

' HashTable ... Object型
Dim ht_name As New Hashtable   ' 宣言
ht_name.Add(keys, value)       ' 追加
ht_name.Count                  ' 要素数取得
ht_name.Item(key)              ' 要素の取得
ht_name.ContainsKey(key)       ' キーの検索(bool)
ht_name.ContainsValue(value)   ' 要素の検索(bool)
ht_name.Remove(key)            ' 指定の要素を削除
ht_name.Clear()                ' すべての要素の削除

    ' 先62日文の日付を候補とする仕様(ex.今日6/12->8/12まで)
        ' 連想配列+(二次元)配列を候補に利用
        ' {"6月":[12,13,14,...],"7月":[1,2,3...],"8月":[1,2,..,12]} '{}..hashtable, []..arraylist


' Dictionary ... 型指定あり, 基本こっちを使おう
Dim dict_name As New Dictionary(Of data_type, data_type)  ' 宣言
' あとは大体上と同じ(なはず)
```

#### **配列最大数取得**

```vb
'配列の最大数を取得する。
UBound(arrey)

#### **タプル**
```vb
Dim list_name As New List(Of Tuple(Of String, String, String))
Dim tuple_name1 As New Tuple(Of String, String, String)
 ("value1", "value2", "value3")
Dim tuple_name2 As New Tuple(Of String, String, String)
 ("value4", "value5", "value6")
list_name.add(tuple_name1)
list_name.add(tuple_name2)
' {(value1, value2, value3), (value4, value5, value6)}
' タプル... 要素の"変更", "削除"ができない配列みたいなもの。
' 例えば個人情報("名前", "住所", "電話番号"..)を１セットとして
' リストに格納していく、みたいな使い方をする(個人情報リスト)
```

## 分岐
#### **If文**
```vb

If conditional_expression1 Then 'conditional_expression ... 条件式
	statements1 ' 文、処理
Else If conditional_expression2
	statements2 ' 文、処理
Else If Not conditional_expression3
	statements3 ' 文、処理
Else
	statementsX ' 文、処理
End If
```

#### **Select-Case文**
```vb

Select conditional_expression Then 'conditional_expression...条件式
	Case valueN ' conditional_expression = valueN の場合
    	statements1
    Case Else   ' default
    	statementsX
End Select
'VBのSelect-Caseは、一つのcaseにしか分岐しない
'(処理の末尾に暗黙的にbreak文が入っている感じ。)
```

## 反復
#### **For文 - 指定した回数文繰り返す**
```vb

For counter_variable [As date_type] = default_value To last_value _
  [Step step_value] 'step_value ... 進行条件の値、[]は省略可能
	statements
Next [counter_variable]
```
#### **While文(Do-While文) - 条件式がTrueの間繰り返す**
```vb

' 前判定
Do While conditional_expression 'conditional_expression...条件式
	statements
Loop
' 後ろ判定
Do
	statements
Loop While conditional_expression 'conditional_expression...条件式
```
#### Until文(Do-Until文) - 条件式がTrueになるまで繰り返す

```vb
' 前判定
Do Until conditional_expression 'conditional_expression...条件式
	statements
Loop
' 後ろ判定
Do
	statements
Loop Until conditional_expression 'conditional_expression...条件式
```

#### **For-Each文(コレクションから繰り返し)**

```vb

For Each variable_storing_elements In Collection 	
    statements ' コレクションの要素の数分繰り返す
Next [variable_storing_elements] 
' variable_storing_elements ... 要素を格納する変数
```

#### **Exit文 - コードブロックの実行を途中終了(Break文みたいなもの)**
```vb

'For文/For-Each文の場合
For ~
	statements
    ExitFor
Next
'While文/Until文の場合
Do While/Until ~
	statements
    ExitDo
Loop
```

#### **Continue文 - 実行制御を次の反復処理に移す**
```vb

'For文/For-Each文の場合
For ~
	statements
    Continue For
Next
'While文/Until文の場合
Do While/Until ~
	statements
    Continue Do
Loop
```

## 例外処理 ... エラーをチェックする
#### **try-catch-finally文**
```vb

Try
    ' エラーをチェックする処理
    checked_statements
Catch variable As System.Exception ' もしエラーがあれば
    ' エラーに対応する処理
    error_supported_process 
Finally
    ' エラーをチェックする処理が終わった後に必ず実行する処理
    absolutely_execute_process 
```

#### **Throw文 ... 例外の強制的な生成**

```
Throw New Class_Name()
```

## クラス
#### **アクセス修飾子**
```vb

Private Class Cl1   '同一の型に含まれる要素からのみアクセス可能
Protected Class Cl1 '同一の型またはその派生型に含まれる要素からアクセス可能
Friend Class Cl1    '同一のアセンブリに含まれる要素からのみアクセス可能
Protected Friend Class Cl1 'Protected or Friendでアクセス可能
Public Class Cl1    'アクセス制限なし
```
###### (以下、アクセス修飾子はPublicで統一)

#### **クラスを利用する**
```vb
Public Class Class_Name2
    ' フィールドの定義
    Public variable_name As data_type ' グローバル変数
    Public Shared variable_name As data_type = value '共有メンバー
    Public Property procedure_name As data_type 'プロパティ

    ' メソッドの定義
    Public Sub procedure_name()
        ' 宣言(名前空間は省略)
        Dim object_variable_name As Class_Name1
        object_variable_name = New Class_Name1()
        Dim object_variable_name As Class_Name1 = New Class_Name1()
        Dim object_variable_name As New Class_Name1()

        object_variable_name.method()    ' subメソッドの実行
        object_variavle_name.method(arg) ' functionメソッドの実行
        object_variable_name.property    ' プロパティ(データ)へのアクセス
        Class_Name1.member               ' 共有メンバーの呼び出し
        object_variable_name = Nothing   ' 参照の終了
    End Sub
End Class

Public Partial Class Class_Name2 ' Partialクラス(上クラスの続き)
...
End Class
```



#### **プロシージャ(メソッド)**

```vb

'Subプロシージャ - メソッド/処理
Public Sub procedure_name([parameter As data_type]) 
    stetements
End Sub

'Functionプロシージャ - メソッド/処理
Public Function procedure_name([parameter As data_type]) 
              As data_type_of_return_value
    statements
    Return return_value
End Function

'この二つは処理なので呼び出しには()をつける
object_variable_name.method()
```

```vb

' Propertyプロシージャ(基本) - フィールド/データの定義
Public Property procedure_name() As data_type '基本的にPublic
	Public Get
    	Return _return_value '読み取りに対する処理例
    End Get
    Public Set(value As data_type)
    	 _return_value = value '書き込みに対する処理例
    End Set
End Property

Private _variable_name As data_type ' ↓専用プロパティのために仮定義

' Propertyプロシージャ(読み取り専用)
Public ReadOnly Property procedure_name() As data_type
    Get
        Return _variable_name '読み取りに対する処理例
    End Get
End Property

' Propertyプロシージャ(書き込み専用)
Public WriteOnly Property procedure_name(value As data_type) As data_type
    Set
        _variable_name = value '書き込みに対する処理例
    End Get
End Property

' Propertyプロシージャ(自動実装プロパティ)
Public Property procedure_name As data_type           '基本
Public ReadOnly Property procedure_name As data_type  '読み取り専用
Public WriteOnly Property procedure_name As data_type '書き込み専用

'これはフィールドの定義なので呼び出しには()はいらない
object_variable_name.member
```

#### **値渡し(ByVal)と参照渡し(ByRef)**
```vb

' 値渡し(コピー/元変更なし)
Public Sub/Func procedure_Name(ByVal variable...)
' 参照渡し(参照/元変更あり)
Public Sub/Func procedure_Name(ByRef variable...)
```

#### **オーバーロード**
```vb

' "Overloads"キーワードは全部につけるか、全部につけないか統一する
Public Class Class_Name1
    Public [Overloads] Sub procedure_name1()
        statements1
    End Sub
    Public [Overloads] Sub procedure_name1(ByVal variable_name1 As data_type1)
        statements2
    End Sub
    Public [Overloads] Sub procedure_name1(ByVal variable_name1 _
         As data_type2, ByRef variable_name2 As data_type1)
        statements3
    End Sub
End Class
```

#### **コンストラクター(フィールドの初期値の設定)**
```vb
Public Class Class_Name1
    [Public] Sub New(parameter1)
        Me.member1 = value1
        Me.member2 = value2
    End Sub
    [Public] [Overloads] Sub New(parameter1, parameter2)
        Me.member1 = value3
        Me.memner2 = value4
    End Sub
End Class
```

#### **名前空間**
```vb

NameSpace name_space_name1
    NameSpace name_space_name2
        Public Class Class_Name1...
    End NameSpace
    NameSpace name_space_name3
        Public Class Class_Name2...
    End NameSpace
End NameSpace

Imports name_space_name1.class_name  ' 先頭にimport文記載の場合
name_space_name1.class_name.method() ' 直接完全修飾子記載の場合
'ほかVSの設定ファイル->参照-インポートされた名前空間から設定も可能
```

#### **継承**
```vb
Public Class Class_Name1 ' 基本クラス
    Sub New(value1 As Integer, value2 As Integer)
        Me.member1 = value1
        Me.member2 = value2
    End Sub
    Public Sub procedure_name1()
    End Sub
End Class

Public Class Class_Name2 ' 派生クラス
    Inherits Class_Name1 ' 継承
    Sub New(value1 As Integer, value2 As Integer, value3 As String)
        ' 基本クラスのコンストラクタの呼び出し
        MyBase.New(value1, value2) ' コンストラクターが継承されていないので
       'Me.member1 = value1 ←↓
       'Me.member2 = value2 ←↓
        Me.member3 = value3
    End Sub
End Class
```
#### **多態性**
##### オーバーライド
```vb
Public Class Class_Name1 ' 基本クラス
    public Overridable Function procedure_name1 As data_type
        statements1
    End Function
End Class 

Public Class Class_Name2 ' 派生クラス
    Inherits Class_Name1
    Public Overrides Function procedure_name1 As data_type
        statements1
        statements2
    End Function
End Class 
```
##### インターフェース
```vb
Interface IInterface_name1 ' インターフェース名: I+CamelCase
    Function procedure_name1() As data_type1 ' 呼び出しクラスが定義
End Interface

Public Class Class_Name1
    Implements IInterface_name
    Public Function procedure_name1() As data_type1 _
      Implements IInterface_name.procedure_name1 '必ず呼ぶ必要あり
        statement
    End Function
End Class
```

#### **ほか**
##### 共有メンバー(Shared修飾子)
```vb

Public Class Class_Name1
    Public Shared variable_name As data_type = value
End Class
Class_Name.variable_name ' オブジェクト変数ではなくクラスから直接
```
##### モジュール
```vb

Public Module module_name
    ' 特徴1. すべてが共有メンバー
    module_name.member
    ' 特徴2. インスタンス生成不可
    Dim variable_name As New module_name() '-> error
    ' 特徴3. 継承不可
    Inherits module_name '-> error
End Module
```


##### 構造体

```vb
Public Structure sturucture_name1
    ' 特徴1. 初期化子による初期化はできない
    Public Shared test As Integer = 0 '-> error
    ' 特徴2. 継承できない
    Inherits structure_name2 '-> error
    ' 特徴3. 独自にコンストラクターの定義ができない
    Sub New() : End Sub '-> error
    ' 特徴4. 値型(<->参照型)
End Structure
##### enum(列挙型)
```vb
' 変更できない整数値(Byte, Short, Int ,Long, U~型)の列挙型
Enum Enum_name As Integer
    member1
    member2
    member3 = 0
    member4 = 5
End Enum

Dim en As enum_name
en = Enum_name.member1

' Enum.GetValues() ... 全ての値を列挙
For Each i In [Enum].GetValues(GetType(enum_name))
    Console.WriteLine(i)
Next

' Enum.TryParse
[Enum].TryParse(Of enum_name)("member5", 4)

' Enum.Parse
' <Flags>属性

' .NETでの構造体はメソッドやプロパティ、インターフェイス　パラメータ化された
' コンストラクタを持つことが出来る。
' 構造体は値型である。また継承はできず、
' イベントを扱うこともできない少量のデータなどを扱う際は有効である。
```


##### 抽象クラスと抽象メソッド
```vb
MustInherits Class Class_Name1 ' 抽象クラス
    ' 特徴1. オブジェクト生成(new)できない
    ' 特徴2. 継承前提
    ' 特徴3. 抽象メソッド(抽象クラスにしか定義できない)
    Public MustOverrides Function procedure_name1() As data_type
    ' 特徴3-1. 宣言のみのメソッド
    ' 特徴3-2. 派生クラスでオーバーライドしなければならない
End Class

Public Class Class_Name2
    Inherits Class_Name1
    Public Overrides Function As data_type ' 必ずオーバーライド
        statements
    End Function
End Class
```
+ [参考:抽象クラスとインターフェースの違い](https://qiita.com/IganinTea/items/e1d35db0a14a84bda452)
+ 
##### ジェネリッククラス
```vb
Sub ClassName(Of T)(Value1 as List(Of T)
'Tは引数として受け取った型

 Dim properties As PropertyInfo() = GetType(T).GetProperties()  'TのPropertyを取得
 Dim count As Integer = properties.Length  'Property数を確認

 For ii As Integer = 0 To count - 1
     vName = properties(ii).Name 'Propertyの名前を取得
     Dim getProperty As PropertyInfo = GetType(T).GetProperty(svName) 'Property名から実際のデータのPropertyを取得
     Dim value = getProperty.GetValue(pData)       '格納されているProperty値を取得
  Next

End Sub

Dim pValue as List(Of localClass1)
ClassName(pValue)
Dim pValue2 as List(Of localkClass2)
ClassName(pValue2)

'Tクラスにはインターフェースを実装する事は出来る。
'(Of T as インターフェース）や(Of T as New) などを使用すれば
Dim pValue as New T 'などが出来る
```



##### With文
```vb
With Object_Variable
    .member1 = value1
    .member2 = value2
    .member3 = value3
    .method()
End With
```
##### デストラクターとオブジェクト破棄

```vb

Public Class Class_Name1
    'デストラクター(Finalize)
    Protected [Overrides] Sub Finalize()
        statements ' 終了処理
    End Sub

    ' Disposeメソッド(手動で強制オブジェクト破棄)
    variable_name.Dispose()

    ' Usingステートメント
    Using object_variable_name As New Class_Name1
        ' 最後に自動的にDisposeメソッド呼び出しするスコープ
    End Using
End Class
```
##### データベース操作(詳細は下で説明)
##### 統合言語クエリ (LINQ) 
```vb
Dim query_name = _
 From iteration_variable1 As data_type In data_source1 _
  Join iteration_variable2 As data_type In data_source2 _
   On iteration_variable1.item_name1 Equals iteration_variable2.item_name2
    Order By iteration_variable1.item_name1
     Where conditional_expression 
      Select item_variable1 = output_item1, item_variable2 = output_item2
' ほかにもgroupbyなど

```vb

Public Class Class_Name1
    ' オブジェクト変数定義
    Dim variable_name1 As New SqlConnection()
    Dim variable_name2 As New SqlCommand()
    Dim variable_name3 As New SqlDataReader()
    
    ' 接続方法の定義
    variable_name1.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("CONNECTION_STRING").ConnectionString
    variable_name2.Connection = variable_name1

    Try
        ' 接続
        variable_name1.Open()

        ' 操作(SQL文:返り値なし)
        variable_name2.CommandText = "SQL_STATEMENTS1";
        variable_name2.CommandType = variable_name2.CommandText
        variable_name2.ExecuteNonQuery()

        ' 操作(SQL文:返り値あり1)
        variable_name2.CommandText = "SQL_STATEMENTS2";
        variable_name2.CommandType = variable_name2.CommandText
        variable_name3 = variable_name2.ExecuteReader()
        Do While variable_name3.Read()
            Console.Writeline(dr("KEY_NAME"))
        Loop

        ' 操作(SQL文:返り値あり2)
        variable_name2.CommandText = "SQL_STATEMENTS3";
        variable_name2.CommandType = variable_name2.CommandText
        ' 実行した結果一つだけ
        variable_name2.ExecuteScalar()
        
        
        ' 操作(SQL文:返り値あり3 - ストアドプロシージャ)
        variable_name2.CommandType = variable_name2.StoredProcedure
        If variable_name2.Parameters.Count = 0 Then
            variable_name2.Parameters("@EmpName", SqlDbType.VarChar, 40)
            variable_name2.Parameters("@EmpName").value = "String"
            variable_name2.Parameters("@EmpName").Direction = ParameterDirection.Input
        Else
            variable_name2.Parameters("@EmpName").value = "String"
        EndIf            

    Catch ex As Exception
        Console.WriteLine(ex.ToString)
    Finally
        ' 切断
        variable_name1.Close()
    End Try
End Class
```

##### テスト
```vb

' 単体テスト
<TestClass[()]> ' テストを含むクラス
Public Class TestClass1
    <TestMethod[()]> ' テストメソッド
    ' ( <ClassInitialize[()]> 単体テスト実行の最初に一度だけ呼び出される
    ' ( <TestInitialize[()]> 各テストメソッドの実行前に必ず呼び出される
    ' ( <TestCleanup[()]> 各テストメソッドの実行後に必ず呼び出される
    ' ( <ClassCleanup[()]> 単体テスト実行後に一度だけ呼び出される

    <TestCategory("Category_Name")> ' テストカテゴリー
    <Owner("Test_Representative")>　' テスト担当者
    <Priority(No)>                  ' 優先順位(1最小)
    Public Sub Test_Method_Name1()
        ' TODO: テスト ロジックをここに追加してください <- おまじまい

        ' Assertクラス
        Assert.AreEqual<data_type>(object1, object2) ' <=> AreNotEqual()
        Assert.IsNull(object)                        ' <=> IsNotNULL()
        Assert.IsTrue(boolean)                       ' <=> IsFalse()
        Assert.IsInstanceOfType(object)              ' 型チェック <=> IsNotInstanceOfType() 
        Assert.Inconclusive()                        ' テスト結果の成功失敗が判断できない
        Assert.Fail                                  ' テストを強制的に失敗とする

        ' StringAssertクラス
        StringAssert.Contains("String1","String2")      ' 文字列1から文字列2を検索
        StringAssert.Matches("String", Regex)           ' 文字列と正規表現が一致するか
        StringAssert.StartsWith("String1", "String2")   ' 文字列1が文字列2で始まるか
        StringAssert.EndWith("String1", "String2")      ' 文字列1が文字列2で終わるか

        ' CollectionAssertクラス
        CollectionAssert.Contains(Collection, Object)         ' コレクションの中にオブジェクト存在するか検索
        CollectionAssert.AreEqual(Collection1, Collection2)   ' コレクション1,コレクション2が同じか
        CollectionAssert.AllItemsAreUnique(Collection)        ' コレクションの値が一意であるか
        CollectionAssert.AllItemsAreInstancesOfType(Collection, Type)  ' コレクション内の値がすべて指定した型か
        CollectionAssert.AllItemsAreNotNull(Collection)       ' Nullが存在するか検索(×null存在)

        CollectionAssert.IsSubsetOf(Collection1, Collection2) ' コレクション1がコレクション2のサブセットであるか

        CollectionAssert.IsSubsetOf(Collection1, Collection2) ' コレクション1がコレクション2のサブセットであるか
    End Sub

    <TestMethod()>
    'SqlServerの利用
    <DataSource("System.Data.SqlClient",
     "Data Source=localhost;Integrated security=SSPI; Initial Catalog=DBNAME;",
     "TABLENAME", DataAccessMethod.Sequential)>
    'Accessの利用
    <DataSource("System.Data.Oledb",
     @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=FILEPATH",
     "TABLENAME", DataAccessMethod.Sequential)>
    ' Excelの利用
    <DataSource("System.Data.OleDb", 
     "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=FILEPATH;Extended Properties=""Excel 12.0;HDR=YES""",
     "SHEETNAME$", DataAccessMethod.Sequential)>
    Public Sub Test_Method_Name2()        
        Dim variable_name As Integer = TestContext.DataRow[.item]("ROWNAME") ' 特定の行の特定のROWNAMEの値を取り出す
    ' https://msdn.microsoft.com/en-us/library/system.data.datarow(v=vs.110).aspx
    End Sub

    ' UIテスト(Only VS Ver.Enterprise)
    <TestMethod()>
    Public Sub Test_Method_Name3()
        ' 
        Dim variable_name1 As WinClient = Me.UIForm1Window,UIFormClient
        ' 
        Dim variable_name2 As WinEdit = Me.UIForm1Window,UIItem0Window.UITextBox1Edit
        ' 
        Dim variable_name3 As WinEdit = Me.UIForm1Window,UIItem0Window.UITextBox2Edit
        ' 
        Dim variable_name4 As WinButton = Me.UIForm1Window,UIItem0Window.UITextBox1Edit
    End Sub

    MouseClick(variable_name1, New Point(x, y))
    variable_name2.Text = value
    variable_name3.Te
End Class
```

##### **#Region**
```vb

#Region "block_name"　' 
' VisualStudioで折り畳み可能なブロック(-/+)
#End Region 
```

##### 禁忌
```vb

Public Class Test1()
    'goto文(Reason: コードが追えなくなる、可読性の低下)
    Label1
        statements
    Public Sub jump()
        goto Label1 ' Label1と記載されている位置にジャンプ
    End Sub

    ' Callステートメント
    Dim test_object As New Ctest1
    test_object.test()      ' 同じ
    Call test_object.test() ' 同じ
End Class
Public Class Ctest1() 
    Public Sub test()
    End Sub
End Class
```
[参考：vbでのcallステートメントについて](https://teratail.com/questions/24577)

## Tips
+ 先頭に'''を入れる->\<Summary>\</Summary>などの情報が自動挿入(VisualStudio)
+ 自身のフォーム … “Me”キーワード
+ \#Region - #End Region ... 展開/折り畳みのできるコードブロックを指定
+ Console.WriteLine(値)でコンソールに値を出力
+ $”文字列(変数名)(改行コードなど)
+ デリゲート ... [参考:デリゲート(delegate)の説明(VB, C#)](https://qiita.com/UWControl/items/906998a80bc72bcdb537)
+ [callが非推奨と言われている理由が書いてある記事です。](www.atmarkit.co.jp/fdotnet/chushin/greatblogentry_01/greatblogentry_01_01.html)

****

##　データベース
#### **ADO.NET**
.NET　FrameworkにはデータアクセスのためにADO.NETが提供されています。
ADO.NETを使用すると.NETで作成できる様々なアプリケーションを作成することができます。
#### **フォーカス**
階層システムを設計する際に　スケーラビリティを配慮する必要があります。スケーラブルなシステムを構築するためにはデータソースとの接続時間を気にする必要性があります。ADOはデータへの疎結合をサポートしているので、データベースサーバへのアクセス集中を低減させる効果を持ちます。
#### **非接続モデル**
ADOが提供するオブジェクトでDateSetを利用するとソースから読み込んだデータをメモリに格納する事ができ、アプリケーションからはメモリ内のデータを利用するためにソースから接続を開放できるというメリットがあり、またデータの変更などはメモリに対して行い変更されたデータを書き戻すときだけまたソースに対して再接続を行います。このような「最低限必要な時だけ接続を行う。」ということは非接続型モデルといます。

#### **データプロバイダ**
ソースに接続してクエリを実行したりするためのオブジェクトを提供しています。
#### **クエリ**
クエリについて
クエリを利用するとデータベースのデータを簡単に表示、追加、削除、変更できます。

特定の抽出条件でフィルター処理することで、特定のデータを素早く検索する


データを計算または集計する。

最新のデータを定期的に検証するなどのデータ管理タスクを自動化する。

#### **DataSet**
データセットオブジェクトはクライアントコンピューターのメモリ上で「仮想的なリレーショナルデータベース」と考えることができます。
テーブル単位でデータを格納するためにDateTableオブジェクトや　テーブル間でリレーションシップを定義するために　dateRelationオブジェクトなどが提供されています。

 ※datesetにはデータベースに接続する機能はないので、データの取得　やり取りなどはデータプロバイダを利用してください
#### **データプロバイダ**
##### 機能
データプロバイダはデータベースに接続して、クエリを実行したときに利用します。
この際に複数のオブジェクトを組み合わせて使用します。　
データベースの接続は[Connection]で行い
選択クエリや更新クエリなどは[Command]で行い
クエリで行った命令に対して返される結果は[DateReader]で行われます。
これらは**オブジェクト**である。
##### 特徴として　
データプロバイダが提供するDateReaderオブジェクトは高速読み取り専用のアクセスができるため、検索結果を表示するのに適しております。DateRederは一行ずつ処理を行うので、メモリには常に1件分のデータしか存在しませんので、データ量とメモリの使用率は関係性を持ちません。

#### **データベースとの接続**
##### コネクション
名前空間を利用してデータプロバイダを利用できるようにする。

```vb

System.Data.SqlClient       '.NET Framework Data Provider for SQL Server

System.Data.OleDb           '.NET Framework Data Provider for OLE DB

System.Data.Odbc            '.NET Framework Data Provider for ODBC

System.Data.OracleClient    '.NET Framework Data Provider for Oracle

```   
データプロバイダの構成の核

|Object|説明|
|---|---|---|---|
|Connection|特定のデータソースへの接続の確立|
|command|データソースに対してコマンドを実行|
|DateReader|前方参照専用で読み取り専用のデータを読み取り|
|DateAdater|datesetに読み込み変更などを行う|

##### 接続
接続するにあたってクラスを利用して接続メソッドを使用します。
接続文字列という前情報をもってメソッドを使用する手順である。
この設定は利用するクラスのConnectionString プロパティにて指定します。
指定する際はセミコロンで区切った形で利用いたします。

|キーワード|説明|規定値|
|---|---|---|
|DateSourceまたはServer,address,addr,Network Address|接続するSQLサーバのインスタンスの名前(ネットワークアドレス)|
|Initial CatalogまたはDatebase|データベース名|
|IntegratedSecurityまたはTrusted_Connection|使用できる値はtrue,False,Yes,No,SSPI。SSPI,Yes,Noは現在のwinアカウントのライセンスが認証に使用されますFalseの場合IDとPWを接続文字列で指定を行ってください|False|
|ConnectTimeoutまたはConnectionTimeout|サーバへの接続時間を待機時間この時間が経過するまでは再接続を繰り返します。この時間が経過した後は終了エラーを返します。|15|

接続を行ったら必ず接続を閉じなければならない
サンプルでは認証を行い接続を閉じます。

#### **サンプル**

```vb

Dim hogeConnectionString AS string = string.Emoty

hogeConnectionString &= "Date Source =serverNAme;"

hogeConnectionString &= "Initial Catalog = Nortwind;"

hogeConnectionString &= "Integraed Security = SSPI;"

'接続文字列の指定
Dim hogeSqlConnection As New system.DataSqlClient.SqlConnection(hogeConnectionString)

'データベース接続を開く

hogeSqlCOnnection.Open()

'接続確認

MessageBox.show("接続を確認いたしました。")

'データベース接続を閉じる。

hogeSqlConnection.Close()
hogeSqlConnection.Dispose()

```

Dispose()  を使用したのですがGCに任せずに開放を行いました。複数アクセス時にデータの変更などから多重で行ってしまった場合に参照する値などに誤差が生まれてしまうと予想したので追加です。

## **動的プロパティによる変更**

参照からsystem.configurationを名前空間へ

ソリューションエクスプロラーからMy projectをダブルクリック
設定タブをクリック　App.configに登録する項目を入力します。
名前　型　スコープ　値
を入力設定行ったら保存をします。
保存を行うと自動的にApp.configに反映されます。
App.config内を変更しても利用は可能になる。
※変更した時は保存を忘れないように


## **クエリ+α**
```vb
Dim hogecone As New SqlConnection
hogecone.ConecetionString = _
    "Data Source = [サーバ名];"&}_
    "Initial Catalog = [データベース名];"&_
    "Integerated Security = SSPI"

hogecone.Open()
Dim hogecoma As New SqlCommand

'コネクションの設定
hogekone.Connetion = hogecone

'コマンドタイプをテキストに
hogecoma.CommandType = CommandType.Text

'実行するSQL
hogecoma.CommandText &= "SELECT * "
hogecoma.CommandText &= "FORM [テーブル名]"
                   '↑  ↑は必ず半角スペースを空けないとエラーになる場合がある。
'SQLの結果を取得
Dim Hoget As SqlDateReader
Hoget = hogecoma.ExecuteReader()
hogecoma.Dispose()
'hogetを利用してデータの表示などを行う。
'コネクションの破棄
If hogecone.State <> ConnectionState.Closed Then
         hogecoma.Close()
         hogecoma.Dispse()
End If

```

##SQL文パラメータ
```vb

"SELECT * FROM Hoge " _
&"WHERE hoge_Id=@hogeId"
[変数].Parameters.Add("@hogeId",SqlDbType.Int)
[変数].Parameters("@hogeId").Value =
       CInt(textBox1.Text)

```
パラメータで行うことでSQLインジェクションを予防することができる。



##クラスを作成してリストを作成する。
```vb

'Employeeクラスのリストを作成
Dim emps As New list(of Employee)
Do While dr.Read
    Dim emp As New Employee()
        emp.ID = dr("emp_id")
        emp.Name = dr("emp_name")
        emp.Type = dr("emp_type")

        emps.Add(emp)              'リストに登録
Loop
DataGridView.DataSource = emps     'データグリットビューに表示


Public Class Employee
  public property ID As Integer   '自動参照
  public property Name As String  '自動参照
  public property Type As String  '自動参照

 


```

取り出したい値をクラスにしておいて、配列(list型）を作成すると楽なのでは？



##**DB登録など**
```vb
recordset.AddNew FieldList, Values
'AddNew メソッドを使って、新規レコードの作成と初期化を行います。
recordset.Update 
'各行が個別に更新されます。


```

───────
****

## 実践サンプル
####**継承とプロパティ　コンストラクタ**
####要件
線路名、目的地、定員数、指定席数、自由席数を入力し、登録ボタンを押すと登録完了のメッセージを表示するようにします。

from1
![継承２.PNG](https://qiita-image-store.s3.amazonaws.com/0/257664/8c5d177c-4382-f778-d757-ce42ca973037.png)

from1では「ex」という変数を定義してその変数はExpressクラスで宣言をしてる。



![継承１.PNG](https://qiita-image-store.s3.amazonaws.com/0/257664/3bb51e21-b122-60c1-9d1f-83aa3ebb981c.png)
#### Expressクラス
+ form1で値を受け取りExpressクラスを値を引き渡す。
+ Expressクラスで値を変数に代入してMsgBoxで表示をするテンプレを記入
+ Expressクラスはtreinクラスから継承をしている。

継承について値を受け取っているのだがコード的に明示的では無い気がしたので少し板書で整理をしてみた



![継承.PNG](https://qiita-image-store.s3.amazonaws.com/0/257664/ba38f6ef-7fe9-3f05-05cb-f14abd431371.png)
#### trainクラス
　暗黙的なconstで値をExpressクラスから受け取りpropertyで処理を行い、form1からexによってMsgは呼び出されいる。
 



####**俺的メモ**
##**ReDim**

```vb

ReDim Preserve name(boundlist)

'配列とか構造体。値を繰り返し格納するのに。REDIMを使ってやると割と楽なんじゃね？
'動きとして条件付けたりなんだかで配列、構造体に値を格納したいときに、いちいち一個一個入れたりアドレス管理するのめんどいならREDIM
'使って　取り込みたい物だけREDIMで再格納すればいい、アドレスは適当にｘとか変数作って入れたい数だけとかこんだけ回したいとかそんなときに使えばいいんじゃね？
'だからアドレスは自分で管理してな、
'んでPreserveしないとアドレス管理してもなにしても、結局REDIMで全項目書き換わるから○○アドレスのどこにこれを格納する。ってやらんと行けないから忘れるなよ。

```

##List(of...
私は配列より個人的にリストをこれから使っていきたいのでそのメモです。


```vb
Public Class Hoogetgege
 Public Function ToUpData(Optional ByVal IsAdd As Boolean = True) As Object()
        Dim pDataRow As New List(of Object)
        If IsAdd Then
           pDatarow.Add(Nothing)
        Else
           pDatarow.Add(HogeID)
        End If
        pDataRow.add(Hoge1)
        pDataRow.add(Hoge2)
        pDataRow.add(Hoge3)
        pDataRow.add(Hoge4)
        pDataRow.add(Hoge5)
  
        Return pDatarow.ToArray

   End Function

  Public Property HogeId As Long
  Public Property Hoge1 As String
  Public Property hoge2 As Date
  Public Property hoge3 As Decimal
  Public Property hoge4 As Hoget   'クラス
  Public Property hoge5 As Naget   'クラス

End Class
Public Function Get_Hoge(ByVal pParam As Get_HogeList_Param) As List(Of Hoogetgege)

'DBopen
   ret = New List(Of Hoogetgege)
   Dim pFugagaga As Hoogetgege
   Do Until Ngo.EOF
      pFugagaga = New HoogetgegeWith {
          .Hogeid = Long.Parse(Val(Ngo.Fields("Hogeid ").Value).ToString,
          .hoge1= Ngo.Fields("hoge1").Value,
          .hoge2 = Ngo.Fields("hoge2").Value,
          .hoge3= Ngo.Fields("hoge3").Value,
          Dim pNaget = New Naget(Ngo.Fields("Naget").Value)
          .hoge4= Ngo.Fields("pHoget ").Value,
          Dim pHoget = New Hoget(Ngo.Fields("Hoge").Value)
          .hoge5= Ngo.Fields("pHoget ").Value,
   Loop
   Return ret



'すごく見にくいのと、型がガバガバなのは許してください。メモ程度なので

'ほんとにこれやばいな。。。
```

リストを一覧表示する時にリストの中でクラスが階層になっているListをfunctionの引数に渡して内部でInvokeMemberで展開？しようとしたが階層になっている為、名前解決することができないので、Selectで新規項目を追加して対応

```vb

Dim argList = Get_県内学校List.Select(Function(x) New With {.学校ID = x.市内学校ID, .コード = x.学校.コード}).ToList
Dim ret = ListinDVGfrm.ShowDialog("タイトル", argList, "コード", "名前")


'これも結構がばがばです。
```

##typeOf
```vb
if typeOf hoge Is textBox Then
Else
End if
```
あるオブジェクトがある型にキャストできるかどうかとかを調べるときに使うことが多いと思います。
TypeOf <名前> Is <型>
ブーリアン値で帰ってきます。

#数値チェック
たまにやり方忘れるので

```vb

If Regex.IsMatch(pControl.Text, "^[0-9]{0,9}$") Then  '数値チェック
  hoge.Text = pControl.Text
Else
  L_ErrMsg = "数値を入力してください"
End If

'もしくは
If IsNumeric(pControl.Text) = False Then '数値チェック Not つかってもOK　Microsoft.VisualBasic　DLL
   L_ErrMsg = "数値を入力してください"
End if

```

# 文字数の多い変数を扱う時
```vb
Dim tSql1 As New System.Text.StringBuilder
tSql1.Clear()
tSql1.Append("BEGIN; INSERT INTO benchmark VALUES ") '文字列の結合

```
StringBuilderを使う事で通常の文字結合よりも早く処理をする事が出来る。<br> ループ内で文字数を多く扱う場合などに有効

# INotifyPropertyChanged

```vb:class1
 Sub New()

 cFrom = New ControlFrom

 textbox1.DataBindings.Add("Text", cFrom , "V_名前")
 textbox2.DataBindings.Add("Text", cFrom , "V_年齢")

 End Sub
 Private Sub Validating(sender As Object, e As CancelEventArgs)Handles Textbox1.Validating, textbox2.Validating
 Dim Control As TextBox = DirectCast(sender, TextBox)
 If Control .Equals(textbox1) Then
 cFrom .V_名前 = pControl.Text
 Else If Control .Equals(textbox2) Then
 cFrom .V_年齢 = pControl.Text
   If cFrom .V_Age_Err_Msg <> "" Then
      MsgBox.Show(cFrom .V_Age_Err_Msg)
   End If
 End If
 End Sub
```

```vb:ControlFrom
Imports System.ComponentModel

Public Class C_MSTCOD

 Implements INotifyPropertyChanged
 Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

 Private _V_Name As String
 Private _V_Age As String
 Private _V_Age_Err_Msg As String
 '--------------------------------------------------------------------------
 Public Property V_名前 As String
  Get
   Return _V_Name
  End Get
  Set(value As String)
   SetProperty(_V_Name, value)
  End Set
'--------------------------------------------------------------------------
 Public Property V_年齢 As String
  Get
   Return _V_Age
  End Get
  Set(value As String)
  If Regex.IsMatch(pControl.Text, "^[0-9]{0,9}$") Then  '数値チェック
     SetProperty(_V_Name, value)
  Else
     SetProperty(V_Age_Err_Msg , "数値を入力してください。")
  End If
  End Set
'--------------------------------------------------------------------------
 Public Property V_Age_Err_Msg e As String
    Get
       Return _V_Age_Err_Msg 
    End Get
    Set(value As String)
       SetProperty(_V_Age_Err_Msg  , value)
    End Set
 End Property

'--------------------------------------------------------------------------
 Private Sub SetProperty(Of T)(ByRef storage As T, value As T,
                 <CallerMemberName> Optional propertyName As String = Nothing)
   If Object.Equals(storage, value) Then
      Return
   End If
   storage = value
   OnPropertyChanged(propertyName)
 End Sub
'--------------------------------------------------------------------------
 Public Sub OnPropertyChanged(propertyName As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
 End Sub

 End Property

```

FromClassにあるコントロールを別のクラスにバインドしてPropertyを使用して、値の管理等を行う仕組み
めんどくてやり方を忘れるので記入しました。
両方のクラスでコントロールを操作できたりするので形さえ覚えちゃえば後は楽なのかと思います。

#ExcelObjectの使用

VB.NETからExcelの出力等を行うときに便利になるのがExcelObjectになります。<br>
注意点としては使用する端末にExcelのライセンスが通っている物しか使用する事が出来ません。（確か）
ライセンスが無くExcelがない端末に対してるは[NPOI](https://qiita.com/k-moriscom/items/ef2c2d57b0c72d706e07)等を検討するといいかもしれません。

#### dll参照
```vb
import Microsoft Office 16.0 Object Library
```

※バージョンにあったDLLを参照してください。

#### コード例
簡易的な使用例です。
基本的にExcelでできる事はできます。

```vb

Dim xApp As Excel.Application = Nothing 

Dim xBooks As Excel.Workbooks= Nothing 
Dim xBook As Excel.Workbook= Nothing 

Dim xSheets As Excel.Sheets= Nothing 
Dim xSheet2 As Excel.Sheets= Nothing 

Dim xSheet As Excel.WorkSheet= Nothing 
Dim xSheet2 As Excel.WorkSheet= Nothing 

Dim xRaneg As Excel.Range= Nothing 
Dim xRange2 As Excel.Range= Nothing 

Try
 　xApp = New Excel.Application
 
'Excel使用時のアラート通知をオフ
 　xApp.DisplayAlerts = False
 


Catch ex as Exception
   'エラー処理
Finally
  '解放処理
   Marshal.ReleaseComObject(xApp)
End Try
```
Excelは階層型になっていて
>App　→　Books →　Book →　Sheets → Sheet → Range


上記の順番で利用するとわかりやすいかもしれません。
またExcelObjectはバックグラウンドで実際にExcelを操作してる為メモリ上に展開されます。
なので使用都度、メモリ解放するように注意してください。
また解放漏れの状態で放置すると思わぬバグが発生する可能性があります。