エクセルVBAの構造体(ユーザー定義型)とは
エクセルVBAの構造体(ユーザー定義型)の概要
VBAにおける構造体は、ユーザー定義型とも呼ばれ、異なるデータ型の変数をひとまとめにして新しい型を定義ができる機能です。構造体は、配列と同様に、複数のデータを1つの変数にまとめて扱えるため、プログラムの可読性が向上し、効率的なコードが書くために有効な機能です。
エクセルVBAの構造体(ユーザー定義型))を使う利点
複数の変数を1つにまとめることで、プログラムの可読性が向上する
エクセルVBAに限った話ではありませんが、プログラムで複雑な処理を実行するために、膨大な数の変数やオブジェクトを使用します。
しかし、変数やオブジェクトが多くあると、それにともなってコードが複雑になり、可読性が低下する傾向があります。
このような場合に、構造体(ユーザー定義型)を使用することで、複数の変数をまとめられます。
構造体(ユーザー定義型)、複数の変数を1つにまとめたものを、1つのオブジェクトとして扱えます。
これにより、関連するデータを1つの変数にまとめることができ、コードからプログラムの全体像をイメージしやすくなります。
例えば、名簿の情報を格納する場合、氏名、年齢、性別、生年月日などを個別に変数として管理すると、コードが複雑になり、可読性が低下します。
しかし、構造体を使用すると、これらの情報を1つのオブジェクトにまとめることができます。
また、構造体は、同じ種類のデータを多数格納する場合にも有用です。
例えば、学生の成績を管理する場合、学生の氏名、出席番号、数学、英語、国語などの情報を1つのオブジェクトにまとめられます。
このように、構造体を使用することで、プログラムの可読性を向上させ、データを効率的に管理ができます。
同じ型の変数を複数定義する必要がなくなるため、コードの記述量が削減できる
構造体(ユーザー定義型)を使用する最大のメリットは、同じ型の複数の変数を1つにまとめられる点です。
たとえば、名前、年齢、住所という3つの変数を持つユーザー情報を取り扱う場合、通常はそれぞれの値を代入するための変数を宣言する必要があります。また、それぞれの変数で実行する処理が複雑になればなるほどコードの可読性は下がり、対象となる変数がどのような値をあつかうための変数であるかが見えづらくなってしまいます。
そういったときに構造体(ユーザー定義型)をつかうことで、コードの記述量の減少とともにそれぞれの変数がどういった値を代入するものであるかの理解しやすいものとしてくれます。
以下は構造体(ユーザー定義型)のイメージ画像です。文章だと伝わりにくいですが、視覚的に図で見るとどういった効果があるかわかりやすいと思います。
構造体を利用することで、プログラムの拡張性が高まる
構造体(ユーザー定義型)を利用することで、プログラムの拡張性が高まります。構造体(ユーザー定義型)を使用することで、1つのオブジェクトに複数のデータを格納できるため、将来的に新しいデータが必要になった場合でも、構造体(ユーザー定義型)に新しいフィールドを追加するだけで、既存のコードを変更する必要がなくなります。
例えば、前述のイメージ画像で示した構造体(ユーザー定義型)である「ユーザー情報」には、名前、年齢、住所の3つのフィールドが既に存在している状態ですが、こちらに電話番号や生年月日などのデータを追加したい場合にも、構造体(ユーザー定義型)のフィールドを追加するだけで拡張ができるようになり、将来的なマクロの発展においても柔軟に対応が可能になります。
既存コードを変更することがなく、プログラム(マクロ)を拡張できることは、拡張を容易にする方法のひとつですので、開発をすすめる上でのメリットとして大きなポイントと言えます。
オンラインスクールで現役エンジニアのサポートがあるテックアカデミーがおすすめ。
スキマ時間に学べて仕事も保証。必ず副業、始められます。まずは無料でプログラミング体験
エクセルVBAの構造体(ユーザー定義型)の宣言方法
構造体(ユーザー定義型)の宣言方法
ここからは構造体(ユーザー定義型)の実際の使用方法について説明していきます。
まずは、構造体(ユーザー定義型)の宣言方法ですが、以下のようにコードを書きます。
Type 構造体名 フィールド1 As 型1 フィールド2 As 型2 ' ... End Type
以下の画像のように、構造体(ユーザー定義型)の宣言は、宣言セクション内に記述します。構造体名は任意の名前をつけてください。Typeキーワードから、End Typeまでの間に構造体(ユーザー定義型)として作成したいフィールドを宣言します。
画像では、フィールド1として、氏名を文字列(String)型、フィールド2を年齢として長整数(Long)型、フィールド3が生年月日の日付(Date)型、フィールド4が血液型の文字列(String)型として4つのフィールドをもつ構造体(ユーザー定義型)を構造体という名前で宣言しています。
同じ名前の構造体(ユーザー定義型)を宣言することはできない
'構造体(ユーザー定義型)は宣言セクションで宣言します。 Type 構造体 氏名 As String '構造体(ユーザー定義型)のフィールド1としてなまえと型を宣言 年齢 As Long '構造体(ユーザー定義型)のフィールド2としてなまえと型を宣言 生年月日 As Date '構造体(ユーザー定義型)のフィールド3としてなまえと型を宣言 血液型 As String '構造体(ユーザー定義型)のフィールド4としてなまえと型を宣言 End Type '複数の構造体(ユーザー定義型)を宣言時は同じ名前だとエラーが発生する Type 構造体 氏名 As String '構造体(ユーザー定義型)のフィールド1としてなまえと型を宣言 年齢 As Long '構造体(ユーザー定義型)のフィールド2としてなまえと型を宣言 生年月日 As Date '構造体(ユーザー定義型)のフィールド3としてなまえと型を宣言 血液型 As String '構造体(ユーザー定義型)のフィールド4としてなまえと型を宣言 End Type
モジュール内のプロシージャを実行しようとするとコンパイルエラーが発生し、名前が適切でない旨のエラーメッセージが表示されます。(※フィールド名が同じであっても構造体(ユーザー定義型)名が異なる場合は宣言は可能です。)
エクセルVBAの構造体(ユーザー定義型)の初期化方法
前項のとおり、構造体(ユーザー定義型)を宣言セクションで宣言できたら、今度は初期化をします。初期化と言ってもプロシージャ内で変数を宣言することと同じなので実に簡単です。
構造体(ユーザー定義型)を初期化する方法
'構造体(ユーザー定義型)は宣言セクションで宣言します。 Type 構造体 氏名 As String '構造体(ユーザー定義型)のフィールド1としてなまえと型を宣言 年齢 As Long '構造体(ユーザー定義型)のフィールド2としてなまえと型を宣言 生年月日 As Date '構造体(ユーザー定義型)のフィールド3としてなまえと型を宣言 血液型 As String '構造体(ユーザー定義型)のフィールド4としてなまえと型を宣言 End Type
Sub mysub1() Dim サンプルユーザー定義型 As 構造体 サンプルユーザー定義型.氏名 = "青木 一郎" サンプルユーザー定義型.年齢 = 29 サンプルユーザー定義型.生年月日 = #4/18/1994# サンプルユーザー定義型.血液型 = "AB" End Sub
エクセルVBAで変数を宣言する方法と同じで、Dim 〇〇(変数名)とコードを書きます。ポイントとなるのは、”As 〇〇”の部分で、宣言セクションで宣言したユーザー定義型(構造体)名をデータ型として指定する点です。
VBAの変数の宣言やデータ型の種類などについての記事はコチラ
エクセルVBAの構造体(ユーザー定義型)の初期化方法
構造体(ユーザー定義型)で宣言した、それぞれのフィールドに値を代入するコードですが、変数名.フィールド名をイコールで値を代入していきます。型の入力やフィールド名の入力時にインテリセンスにより入力候補が表示されるので、対象の項目を選択できます。
インテリセンスとは?
ひとことで言えば、入力支援機能のことです。
詳しく知りたい人はリンクをクリック。(外部サイトに接続します。)
インテリセンス (IntelliSense) は、Microsoft Visual Studio の統合開発環境で使用されている、マイクロソフトによる自動補完システム。インテリセンスはプログラマが入力中のシンボル名を補完するだけでなく、メタデータベースのリフレクションを用いることにより、変数名、関数名、メソッド名のドキュメント化と曖昧性の解消に役立つ。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
宣言セクションで既に宣言しているため、候補リストに表示されます。
今回は”構造体“という名前の構造体(ユーザー定義型)を宣言しましたので、プロシージャ(mysub1)で変数の宣言をすると、選択が可能な候補リストが予測され、その中に”構造体“が表示されていることが以下の画面でわかります。
さらに、それぞれのフィールドに値の代入をするときも、同じように入力補完機能(インテリセンス)がはたらき、候補となるメンバーが表示されることが次の画像でわかると思います。
構造体(ユーザー定義型)の氏名・年齢・生年月日・血液型のフィールドを初期化するコードです。
Sub mysub1() Dim サンプルユーザー定義型 As 構造体 サンプルユーザー定義型.氏名 = "青木 一郎" サンプルユーザー定義型.年齢 = 29 サンプルユーザー定義型.生年月日 = #4/18/1994# サンプルユーザー定義型.血液型 = "AB" End Sub
こうしてコードを見ると、サンプルユーザー定義型という名前の変数が氏名、年齢、生年月日、血液型のフィールドを持っている構造体(ユーザー定義型)であるということがわかりやすいです。
マクロを実行して、構造体(ユーザー定義型)の初期化を実行したときのローカルウィンドウが上の画像です。
それぞれのフィールドに値が代入されました。
構造体(ユーザー定義型)の配列を初期化する方法
前項では、変数を構造体(ユーザー定義型)として宣言しました。
今度は配列を初期化する方法を紹介します。宣言セクションの構造体(ユーザー定義型)のコード部分は変更がありませんので、サンプルコードではsubプロシージャの部分のみ紹介します。
サンプルコード
Sub mysub2() Dim サンプルユーザー定義型(2) As 構造体 '配列の0番インデックスのフィールドを初期化する サンプルユーザー定義型(0).氏名 = "青木 一郎" サンプルユーザー定義型(0).年齢 = 29 サンプルユーザー定義型(0).生年月日 = #4/18/1994# サンプルユーザー定義型(0).血液型 = "AB" '配列の1番インデックスのフィールドを初期化する サンプルユーザー定義型(1).氏名 = "石川 美織" サンプルユーザー定義型(1).年齢 = 34 サンプルユーザー定義型(1).生年月日 = #8/2/1988# サンプルユーザー定義型(1).血液型 = "A" '配列の2番インデックスのフィールドを初期化する サンプルユーザー定義型(2).氏名 = "有働 信二" サンプルユーザー定義型(2).年齢 = 30 サンプルユーザー定義型(2).生年月日 = #11/23/1992# サンプルユーザー定義型(2).血液型 = "O" End Sub
通常の変数と異なる点として、サンプル構造体(ユーザー定義型)を静的配列として宣言している点です。サンプルコードでは、変数名に(2)を追記することで3つの要素をもつ配列にしています。
要素数が3つとなる理由は、配列のインデックスは指定をしない限り0からとなるためです。つまりサンプルユーザー定義型の配列はインデックスが0~2までの3つの要素をもった静的配列です。
配列は要素は0からだから2を指定すると0、1、2の3つだね。
通常の変数のときと同じようにマクロを実行して、ローカルウィンドウを確認していきましょう。
以下の画像は実行したときのものです。それぞれに要素の各フィールドに値が代入されていることがわかります。
こうして見ると、構造体(ユーザー定義型)は、ひと目でわかりやすく値が管理ができ、その値がどういったものであるかがグループ化できることはプログラム全体の読みやすさ(可読性)が向上します。
エクセルVBAで構造体(ユーザー定義型)のフィールドにアクセスする
構造体(ユーザー定義型)のフィールドへのアクセスですが、VBAではドット演算子 (.) を使う方法と、With構文を使う2種類の方法があります。
ドット演算子(.)で構造体(ユーザー定義型)のフィールドへのアクセス
ドット演算子 (.)をつかってのフィールドアクセス方法は既に前項でも紹介しているとおり、以下のように書きます。
構造体(ユーザー定義型)名.フィールド名 = 値
サンプルコード
Sub mysub1() Dim サンプルユーザー定義型 As 構造体 サンプルユーザー定義型.氏名 = "青木 一郎" サンプルユーザー定義型.年齢 = 29 サンプルユーザー定義型.生年月日 = #4/18/1994# サンプルユーザー定義型.血液型 = "AB" End Sub
これで氏名フィールドにアクセスして、”青木 一郎”を代入することができました。
With構文で構造体(ユーザー定義型)名のフィールドへのアクセス
構造体(ユーザー定義型)の変数名をWithステートメントで囲み、各フィールドにアクセスする際には、ドット (.) をつけて、フィールド名だけを記述します。
以下のマクロでは、ドット演算子をつかって、フィールドにアクセスしたコードをWith構文で書き直したものです。
サンプルコード
Sub mysub3() Dim サンプルユーザー定義型 As 構造体 With サンプルユーザー定義型 .氏名 = "石川 美織" .年齢 = 34 .生年月日 = #8/2/1988# .血液型 = "A" End With End Sub
構造体(ユーザー定義型)の応用例
ここまでで、構造体(ユーザー定義型)を使用することで、コード量が少なくなります。その結果、可読性の向上につながり、拡張しやすいものにできることはおわかりいただけたかと思います。
ここではそんな構造体(ユーザー定義型)をつかったプログラムの応用例を2つ紹介します。
構造体(ユーザー定義型)をつかって社員情報を管理する
3名の社員を構造体(ユーザー定義型)の変数として各フィールドに値を代入して出力するプログラムです。
※宣言セクションの書きかたは、前述のとおりでコチラを参考にしてください。
サンプルコード
Sub mysub4() '変数"社員1"を構造体(ユーザー定義型)として宣言する Dim 社員1 As 構造体 '変数"社員1"の各フィールドに値を代入する 社員1.氏名 = "青木 一郎" 社員1.年齢 = 29 社員1.生年月日 = #4/18/1994# 社員1.血液型 = "AB" '変数"社員2"を構造体(ユーザー定義型)として宣言する Dim 社員2 As 構造体 '変数"社員2"の各フィールドに値を代入する 社員2.氏名 = "石川 美織" 社員2.年齢 = 34 社員2.生年月日 = #8/2/1988# 社員2.血液型 = "A" '変数"社員3"を構造体(ユーザー定義型)として宣言する Dim 社員3 As 構造体 '変数"社員3"の各フィールドに値を代入する 社員3.氏名 = "有働 信二" 社員3.年齢 = 30 社員3.生年月日 = #11/23/1992# 社員3.血液型 = "O" '各フィールドの値を出力する Debug.Print 社員1.氏名, 社員1.年齢, 社員1.生年月日, 社員1.血液型 Debug.Print 社員2.氏名, 社員2.年齢, 社員2.生年月日, 社員2.血液型 Debug.Print 社員3.氏名, 社員3.年齢, 社員3.生年月日, 社員3.血液型 End Sub
このコードであれば、新入社員が入社してきた場合などに”社員4“を追加するなどで、簡単にプログラムの拡張ができます。
※こちらでは社員1から社員3と個別に変数をつかっていますが、配列を使う方法でもスッキリとした可読性の高いコードが書けます。
プログラムのコードは見やすさとアップデートのしやすさが大切だよ。
構造体(ユーザー定義型)をつかってCSVファイルを読み込む
応用例の2つ目では、CSVファイルの読み込み方法を紹介します。サンプルデータとなるCSVファイルを準備しましたので、そちらを読み込んで構造体(ユーザー定義型)に代入していきます。
こちらのCSVを読み込んでいきます。
サンプルCSVファイルには、それぞれの行に氏名・年齢・性別・出身地・所属・役職の6つの要素があり、101行目(データとしては100件分)が登録されています。
このCSVファイルの表をデータを読み込んでいくよ。
サンプルコード(宣言セクション)
Type 社員情報 name As String '氏名を代入するフィールド age As String '年齢を代入するフィールド gender As String '性別を代入するフィールド Birthplace As String '出身地を代入するフィールド Affiliation As String '所属を代入するフィールド director As String '役職を代入するフィールド End Type
読み込むCSVファイルのデータを読み取るため、1行あたりに6つのフィールド(氏名・年齢・性別・出身地・所属・役職)をもつ、構造体(ユーザー定義型)を宣言しておきます。
サンプルコード(プロシージャ)
Sub CSVを読み込む() Dim f As Integer f = FreeFile'Openステートメントで使用可能な数値(1~511)が返る 'ファイルの格納場所を指定する Open "C:\Users\XXXX\Desktop\名簿.csv" For Input As #f Dim myArray() As 社員情報 Dim arr As Variant'CSVの行の文字列を代入するための配列 Dim line As String'CSVの行の文字列を格納する変数 Dim i As Integer'インデックス用の変数 Do Until EOF(f) ReDim Preserve myArray(i) Line Input #f, line arr = Split(line, ",") myArray(i).name = arr(0) myArray(i).age = arr(1) myArray(i).gender = arr(2) myArray(i).Birthplace = arr(3) myArray(i).Affiliation = arr(4) myArray(i).director = arr(5) i = i + 1 Loop Close #f End Sub
サンプルマクロに書いている手順としては、以下のとおりです。
01.FreeFile関数で数値を返し、変数に代入する
02.読み込みたいCSVファイルをOpenステートメントで開く
03.CSVファイルの行ごとのデータをLine Input #ステートメントで読み込み変数に代入する
04.行ごとのデータは、氏名・年齢・性別・出身地・所属・役職がコンマで区切った文字列であるため、Split関数をつかって、コンマで区切られた文字列を配列に代入する
05.構造体(ユーザー定義型)に手順4で代入した要素を代入する
それぞれの手順について詳しく解説していきます。ただし、この応用例では、本記事で紹介したい構造体(ユーザー定義型)以外の部分も含むため、それぞれを深掘りはせずどういったことをしているかに留めておきます。
FreeFile関数の戻り値を整数型の変数に代入する
FreeFile関数はOpenステートメントで使用できる数値を返す関数です。1~511までの数値が返ってきます。サンプルコードの場合は、変数fには整数”1″が代入されます。
OpenステートメントでCSVファイルをひらく
Openステートメントはファイルをひらく操作ができます。
pathname For mode [ Accessaccess ] [ lock ] As [ # ] filenumber [ Len = reclength ] を開く
Openステートメントの構文において、指定項目のpathname、mode、filenumberの指定は必須です。サンプルコードで指定項目に指定している値は以下の表のとおりです。
指定項目 | サンプルコードでの値 |
---|---|
pathname | “C:\Users\XXXX\Desktop\名簿.csv” |
mode(Append、Binary、Input、Output、または Random) | Input |
filenumber(1~511) | 1(※変数fに代入された数値) |
CSVファイルの行ごとのデータをLineInputステートメントで変数に代入する
サンプルCSVの紹介でも書きましたが、こちらのCSVファイルには100件分のデータが登録されています。
各行のデータごとに読み込んでいくわけですので、行ごとにくり返し処理が必要になります。なお、こちらのサンプルコードでは、DoUntilステートメントをつかっています。
Do [While|Until]ステートメントは、Forステートメントと異なり、具体的な回数や要素数ではなく、指定した条件の判定の結果にしたがってくり返します。サンプルコードでは、条件としてEOF関数をつかっており、このEOF関数の戻り値がTrueになるまで繰り返す処理を指定しています。
簡単に言えば何も書かれていない行まではくり返すんだね。
つまり、サンプルCSVのDo Loopステートメントでは、CSVファイルの最終行まで繰り返します。
次に処理の内容ですが、最初に配列であるmyArrayの要素数を再定義します。ReDim Preserveをつかうことで代入された値を保持しながら要素数を追加しています。
次に、Line Input # ステートメントをつかって、サンプルCSVファイルの行をコンマで区切ったに文字列に代入していきます。Line Input # ステートメントについては以下のとおりです。
Line Input #ファイル番号, 変数名
サンプルコードでは、サンプルCSVの1行ずつを取り出し、変数lineに代入していきます。
繰り返し1回目の処理では、変数lineに文字列として”氏名,年齢,性別,出身地,所属,役職“が代入され、繰り返し2回目では”まなふ へゆさ,40,男,京都府,営業部,主任“が代入され、3行目、4行目…と処理が繰り返されます。
Split関数でコンマで区切られた文字列を分割し配列に代入する
続いて、Split関数をつかって変数lineに代入した文字列を分割します。Split関数は指定した区切り記号が含まれる文字列を指定して、記号でそれぞれの文字列を分割して配列を返します。
サンプルコードで2回目の繰り返し時の例だと、変数lineには”まなふ へゆさ,40,男,京都府,営業部,主任“が代入されていますので、コンマで区切った文字列を”まなふ へゆさ“・”40“・”男“・”京都府“・”営業部“・”主任“の6つに分割され、1次元配列arrの要素として代入します。
構造体(ユーザー定義型)のフィールドに配列の値を代入する
さいごに、構造体(ユーザー定義型)の各フィールドに配列arrのそれぞれの要素を代入する処理を実行します。
これで、サンプルCSVファイルの101行(100件)分のデータが構造体(ユーザー定義型)で読み込めました。以下の画像はこのマクロで処理が完了した時点のVBEのローカルウィンドウです。
CSVファイルのすべてのデータが、構造体(ユーザー定義型)に代入されました。
社内で使用しているシステムがある場合、そこから出力したCSVファイルなどをあつかう場合などは、構造体(ユーザー定義型)をもちいたサンプルコードのようなマクロをつかうことで、データを効率的に再利用ができます。
また、構造体(ユーザー定義型)をつかうことで、拡張が簡単なマクロが作れるため、将来的にマクロをの発展するときだけでなく、サンプルCSVファイル以外の、さまざまなCSVファイルのデータの読み込みにも対応ができる汎用性が高いマクロとして重宝します。
エクセルVBAの構造体(ユーザー定義型)を取り扱う時の注意点
構造体(ユーザー定義型)は、さまざな種類の型の変数をひとまとめにしてくれる便利な機能であることを説明しました。また、マクロで取り扱う変数をまとめられることで、VBAのコードの可読性が向上したり、アップデートしやすくなります。
そんな便利な構造体(ユーザー定義型)ですが、マクロで取り扱う上での注意点もいくつか存在しますので、ここではいくつか紹介していきます。
構造体(ユーザー定義型)のフィールドのデータ型には制限がある
ユーザー定義型(構造体)のフィールドに設定できるデータ型は、基本的なデータ型とオブジェクト型です。エクセルVBAのデータ型には整数型、浮動小数点数型、文字列型、真偽値型などがあり、これらをフィールドに設定が可能です。
一方、オブジェクト型には、Worksheetオブジェクト、Rangeオブジェクト、Collectionオブジェクト、Dictionaryオブジェクトなどがあり、これらもフィールドとして設定することが可能です。
ただし、クラスモジュール内に定義されたクラスや、ActiveXコントロールのインスタンスなどはフィールドに設定することはできない点に注意が必要です。
構造体(ユーザー定義型)で発生するエラー処理に対応する
構造体(ユーザー定義型)は変数をまとめる上で便利な機能ですが、その特性において、プログラム内でデータの整合性を保つことに注意する必要があります。
構造体のフィールドのデータ型に不正な値が代入されたエラー対処として、使用者にメッセージを表示し、正しい方法を促すことなどの処理を準備しておくことで、マクロやプログラムの異常終了(停止)の発生を未然にふせぐなどの対応が必要です。
エクセルVBAの構造体(ユーザー定義型)に関するまとめ
構造体(ユーザー定義型)の利用方法と注意点
構造体(ユーザー定義型)の宣言方法は、モジュールの宣言セクションにて、Typeキーワードを使用することで実装できます。また、フィールドのデータ型や名前の指定は、プロシージャで使用する他の変数の宣言と同じ書きかたで設定ができます。
構造体(ユーザー定義型)のフィールドへのアクセスには、ドット演算子を使用する方法や、With構文を使用する方法があります。フィールドの値を変更する場合は、代入演算子を使用します。
Withステートメントの使い方はこちらの記事でまとめています。
構造体(ユーザー定義型)を使って、大量のデータを効率的にまとめたり、CSVファイルのデータを読み込む方法もあり、応用例も多数存在します。
複数の構造体(ユーザー定義型)を定義する場合は、それぞれの構造体(ユーザー定義型)名が重複しないように注意する必要があります。
構造体(ユーザー定義型)をつかうことのメリット
ここまでの説明で、構造体(ユーザー定義型)は、複数の変数をひとまとめにできるもので、その効果として、コードの可読性を向上させることや、同じ型の変数を複数定義する必要がなくなることから、マクロにおけるコードの記述量を大きく削減できます。
さらに、実行する処理を書きこむプロシージャとは異なるエリア(宣言セクション)で宣言するためのコードを書きこむため、処理で利用する変数と明確に区別ができ、プログラムやマクロの拡張がしやすいテクニックだと言えます。
今回はここまで。
コダマのもりブログはにほんブログ村に登録しています。
ブログの記事が役に立ったと感じて頂けたら、フォローお願いいたします。
コメント