引数の数が一致していません。または不正なプロパティを指定しています。


不正なプロパティというよりも、引数の数が正しくないときに多く発生します。上図では、セル(Range("A1"))をDeleteメソッドで削除しています。Deleteメソッドは、削除した後、周囲のセルをどちらにシフトするかを引数で指定します。Deleteメソッドに指定できる引数は1つだけです。上図では引数を2つ指定したのでエラーになりました。

このエラーは、メソッドだけでなく、次のように関数の引数が一致していないときにも発生します。

ただし、引数の数が不足しているときには、次のエラーが起こるときもあります。

また、名前付き引数の名称が間違っているときは、次のエラーになります。

プロシージャ名の重複

結果的には「引数の数が一致していない」ことに違いはないのですが、次のようなケースでも、このエラーが発生しますので注意してください。

上図は、Format関数がエラーになっています。「引数の数が一致していない」と指摘されていますが、いくら見直しても、Format関数の引数は間違っていません。Range("A1")には間違いなく日付(シリアル値)が入っていますし、書式記号の"yyyy"がいけないのか?いや待てよ「不正なプロパティ」って言ってるから、もしかするとValueプロパティがいけないんだろうか・・・

実は、エラーの原因はここではありません。このモジュールに、Formatという名前のプロシージャがあったんです。

SubプロシージャとしてFormatを定義した場合、マクロ中で使用するFormatは、関数ではなくプロシージャの呼び出しと認識されます。最初からあるFormat関数より、後から定義されたFormatプロシージャの方が優先されるんです。「MsgBox Format(Range("A1").Value, "yyyy")」はForamtプロシージャを呼び出したことになるのですが、Sub Formatの方には受け取る引数が定義されていません。

Formatプロシージャに2つの引数(Range("A1")と"yyyy")を渡そうとしたけれど、呼び出したSub Formatでは受け取る引数がない(0個と定義されている)ため、引数の数が合いません(一致していません)。だからエラーですと。そういうことです。

こんなときは、Sub Formatのプロシージャ名を変更してください。どーーしても、プロシージャ名を変更できない特別な事情がある場合は、Format関数の呼び出しを次のようにします。

こうすれば、Sub Formatがある状態でFormat関数を使用できますが、あまり推奨はできません。ミスの元です。そもそも、関数と同じ名前のプロシージャ名を定義したのが原因なのですから、素直にプロシージャ名を変更した方がいいです。

名前付き引数について

VBAのメソッドで引数を指定するには2つの方法があります。ひとつは、

対象.メソッド 引き数名:=値

という形式です。メソッドの引数には名前が設定されています。これを名前付き引数と呼びます。名前付き引数に値を設定するとき、その引き数名に値を代入します。そのとき、代入には「:=」という記号を使います。このように、名前付き引数を使うと、複数設定する引数は、あらかじめ定義されている順番通りでなくてもかまいません。

たとえば、ワークシートを挿入するときは、WorksheetsコレクションのAddメソッドを実行します。このAddメソッドには、次のように4つの名前付き引数が定義されています。

Worksheets.Add Before, After, Count, Type

引数Beforeに既存のワークシートを指定すると、そのシートの直前に新しいワークシートが挿入されます。

引数Afterに既存のワークシートを指定すると、そのシートの直後に新しいワークシートが挿入されます。

引数Countには、挿入するワークシートの枚数を指定します。

引数Typeには、挿入するシートの種類(ワークシートやグラフシートなど)を指定します。

次のコードは、Sheet2の直前に2枚のワークシートを挿入します。

Sub Sample()
    Worksheets.Add Before:=Worksheets("Sheet2"), Count:=2
End Sub

このコードは、名前付き引数を使って指定していますので、BeforeとCountの順番が逆になっても正常に動作します。

Sub Sample()
    Worksheets.Add Count:=2, Before:=Worksheets("Sheet2")
End Sub

VBAのメソッドで引数を指定するとき、もうひとつの方法は、

対象.メソッド 値

のように、引数の名前を指定しないやり方です。引き数名や「:=」記号は必要ありません。ただし、このときは、あらかじめ定義されている順番で引数を指定しなければなりません。

先のAddメソッドでは4つの引数を指定できます。引数Beforeと引数Countを、名前付き引数を使わないで指定するには、次のように引数の順番(位置)を正確に指定しなければなりません。

Sub Sample()
    Worksheets.Add Worksheets("Sheet2"), , 2
End Sub

2番目の引数Afterは指定していませんが、指定しなくてもカンマだけは必要です。そうしないと、引数の位置を特定できないからです。

このように、メソッドの引数を指定する方法は2種類ありますが、雑誌や書籍やWebなどの解説では、特に厳格なルールはなく、暗黙の書き方や著者のクセなどによってさまざまな書き方が紹介されています。

たとえば、既存のブックを開くWorkbooksコレクションのOpenメソッドには、とてもたくさんの名前付き引数が定義されていますが、普通のブックを普通に開くだけでしたら「どのブックを開くか」を表す、引数Filenameだけを指定すれば済みます。名前付き引数を使って指定するなら、

Sub Sample()
    Workbooks.Open Filename:="Book1.xls"
End Sub

となりますが、これを

Sub Sample()
    Workbooks.Open "Book1.xls"
End Sub

のように、名前付き引数を使わず、値だけを指定する記述が少なくありません。引数Filenameは一番最初に定義されていますので、両者のコードは同じ意味になります。

セルをコピーするCopyメソッドにも、貼り付け先を表すDestinationという名前付き引数が定義されています。セルA1をセルB1にコピーするとき、名前付き引数を使うと次のようになります。

Sub Sample()
    Range("A1").Copy Destination:=Range("B1")
End Sub

しかし、雑誌や書籍などでは、次のように名前付き引数を省略して解説することが多いです。

Sub Sample()
    Range("A1").Copy Range("B1")
End Sub

雑誌や書籍で、名前付き引数を省略した書き方で解説する理由はいくつかありますが、そのひとつは「ページ幅」の問題です。複数の引数すべてを名前付き引数で指定すると、コードの文字数が多くなります。すると、1行のコードが中途半端に折り返されてしまい、(編集的な)見た目がよろしくありません。なので「名前付き引数は使わない」という方針で執筆することもあります。また、雑誌や書籍は、読者が記事を見ながら、その通りに入力することがあります。その際、少しでも入力する文字の数を減らそうという考えもあります。なぜなら「書いてあるとおりに入力したけど動かない」という問い合わせは、けっこう多いからです。何よりも、名前付き引数について、ビギナーに分かりやすく解説するのは、決して簡単ではありません。メソッドや名前付き引数について正確な知識が必要ですし、ビギナーにも分かりやすい解説を書く文章力や構成力が必要になりますし、その分のページも確保しなければなりません。大変です。大変ですから、名前付き引数の解説はしない→名前付き引数は使わない というパターンも、ないとは言えません。

しかし、セルを削除するときに使うDeleteメソッドなど、名前付き引数を省略しないで解説することもあります。

Sub Sample()
    Range("A1").Delete Shift:=xlToLeft
End Sub

これは、マクロ記録すると名前付き引数が必ず記録されるからです。読者がマクロ記録で得られるコードと、解説のコードが異なっていると「なぜ?どうして?」と混乱する読者がいるかもしれません。本来なら、混乱しないように、詳しく解説をすればいいのですが、その解説を端折るからには、混乱させないために(という理由で)、マクロ記録で生成される通りのコードを解説にも使うことになります。

以上のような理由からか、名前付き引数に関しての解説はあまり多くありません。そのため、名前付き引数を正しく理解していないビギナーも少なくありません。混乱しないように解説を省いた結果、ビギナーはいつまでも混乱し続けていると、私はそう感じています。