[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『派生質問トピックです。』(もこな2)
本トピックは[[20180220235541]]からの派生質疑です。
元トピックと関連が薄い内容になってしまったので、こちらに移設しました。
< 使用 Excel:Excel2013、使用 OS:Windows7 >
↓↓元トピックからの移設
Sortメソッドについても、フォローありがとうございます。
やっぱ基本は、前バージョンとの互換があるから、機能は残ってるんですね。
(もこな2) 2018/02/21(水) 12:40
>>Range(Cells(i, 3)) >なるほど、Rangeオブジェクトに、単一セル渡せば中でキャストしてくれるのかなとおもってましたけど、
キャストって??
何が何になる(と思った)んですか?
>・・とおもったけど、同じセルを第2引数で与えれば単一セルになって、いけそうですね。(試してないですけど) よしましょうよ。
Key1:=.Cells(i, 3) だけで済む話なんですから。
>〜.Sort(Key1:=.Range(.Cells(i, 3),.Cells(i, 3)).Value, Order1:=xlAscending, Orientation:=xlSortRows) >すごく気持ち悪いですし、.Cells(i, 3).Value にしない理由を聞きたくなりますけど・・
何が気持ち悪いのか?? ですね。(私には)
(半平太) 2018/02/21(水) 12:53
>キャストって?? >何が何になる(と思った)んですか? RangeオブジェクトにcellプロパティのRangeがセットされて・・・って言ってて変ですけど・・まぁそうなってくれるのかなと。 試せばエラーになって気づいたでしょうけど試してないんで・・・
>よしましょうよ。 >Key1:=.Cells(i, 3) だけで済む話なんですから。 >何が気持ち悪いのか?? ですね。(私には) 半平太さんと同じ意見ですよ。 第2引数に、同じセルを与えて、Key1:=.Range(.Cells(i, 3),.Cells(i, 3))〜 って記述すれば構文として 間違いではないのかもしれないけど、すごい遠回りしるように感じて「気持ち悪い」ので、 「Key1:=.Cells(i, 3).Value」 にしない理由を聞きたくなりますねってことです。 (私は、Valueプロパティの省略も気になるタイプなので付け足しましたけど) (もこな2) 2018/02/21(水) 13:14
>半平太さんと同じ意見ですよ。
すみません。同じじゃないんですけど。 m(__)m
>「Key1:=.Cells(i, 3).Value」 にしない理由を聞きたくなりますねってことです。 >(私は、Valueプロパティの省略も気になるタイプなので付け足しましたけど)
それは、もこな2さんがSortメソッドのヘルプを読んでいなからです。
古いバージョンを持っていないのが主因なのかも知れませんけど、 私には「None.Value不安症候群」ではないかとさえ思えます。
時にはそんなことすると、有害になることもあるんです。
(半平太) 2018/02/21(水) 13:27
>Sortメソッドのヘルプを読んでいなからです。
たしかに読んでないですね。勉強してみます。
>「None.Value不安症候群」ではないかとさえ思えます。
>時にはそんなことすると、有害になることもあるんです。
ちょっとよくわかりませんでした。
オブジェクトとして扱うべきところで、文字列や数値などの値を渡してしまうことがあるから危険ですよ。って理解でよいですか?
(もこな2) 2018/02/21(水) 13:39
>オブジェクトとして扱うべきところで、文字列や数値などの値を渡してしまうことがあるから危険ですよ。って理解でよいですか?
ほぼその通りです。 もっと、引き下がって見ると、我ら一般ユーザーは、各プロパティ、メソッドの詳細な仕様を知らされていないです。
ご参考になるかも知れないので、以下のコードを載せておきます。 結果を見る前に、E1、E2、E3セルに何が入るか予想してみてください。
Sub Macro1() Range("A2").Formula = "2/21/2018" Range("C2").Formula = "2/21/2018"
Range("E1").Value = Application.Match(Range("C2"), Range("A1:A10"), 0) Range("E2").Value = Application.Match(Range("C2").Value, Range("A1:A10"), 0) Range("E3").Value = Application.Match(Range("C2").Value2, Range("A1:A10"), 0) End Sub
ここは、five-oさんがトピ主なので、本人の質問趣旨から離れ始めましたので、これで止めにします。
(返信なき様にお願いします)
(半平太) 2018/02/21(水) 14:15
もこな2さん
了解です。
上述の例から、「兎に角 .Valueを付けると安心だ」なんてことは言えないことはハッキリしていると思います。
多分、Match関数は、オブジェクトで貰うか、値で貰うことを想定したプログラムになっているんでしょうが、 Date型の値データではその状況下ではヒットできないように作られている(意図的かどうかは別として)。
我々は何故ダメなのか分からない。仕様の詳細が分かんないですから当然ですね。 しょうがないので、経験で仕様を逆算して考えるしかないですが、限界があります。
・・にも拘らず、.Valueプロパティにすると安心できると言うのは「幻想」とまでは言わないが、 過信・盲信気味ぐらいには考えています。
あと、話が少しずれますが、値を与える場面でも.Valueをチャンと付けようよなんて意見が大勢で、 インストラクターのネタ帳さんは、「.Valueくらい付けましょうよ」とか偉そうに言っているけど、 値しか貰えない場面なら、当然なんだから「そんなもの付けないでいいでしょう」と言うのが私の持論です。
・・多分、これには反対論が多いでしょうけどね・・
値しか貰えない場面かどうかさえ分かんない人は、自分の無知の代償として付けるしかないです。 (ただ、付けたって旨く行く保証はないですよね。仕様を知らないんですから。)
私自身も分かんない時は多々あります。けど、馬鹿の一つ覚えみたいに付けるのはいやですね。 まぁ現実には、余り人とぶつかるのもいやなんで、穏便路線を選んじゃったりしていますけど。
(半平太) 2018/02/21(水) 17:22
私なんぞ「将来、既定のプロパティが変更されたり、既定のプロパティが廃止されたりしないだろうか・・・」 なんて、ほぼ妄想レベルの事を想定(心配?)して.Value付けたりしちゃってますねぇ^^;
>値しか貰えない場面なら、当然なんだから「そんなもの付けないでいいでしょう」 これなんかも 私に言わせれば「値しか貰えない場面なんだから、自信持って付けれるじゃん。付けとこー」 ってなってしまいます。
そう言っておきながら、ついつい付け忘れしまい、かなり後になってから発見したり はたまた、ひとしきり付け終った後に、ざっと見返してみて「わぁ...ごちゃごちゃ見辛いわ消そ」とか^^; (まぁ、そんなレベルの者の意見ってことですね^^;)
とは言え、既定のプロパティ便利だし、やっぱ頼りますね。
シート上での使用を想定したFunctionプロシージャで、 特に配列を渡す(つもりの)引数をVariant型で表現したりする場合なんかは、 実際、変数の中身がRangeオブジェクトなのか配列なのか、ちゃんと判定する必要に迫られる事もありますが、 大抵の場合は変数の中身がどちらであろうが、そのまま配列として扱って済む処理が多いので 結果的にイテレート内で既定のプロパティに頼ってしまってるじゃん その方がコーディングの手間省けるじゃん
とか。
そんなこんなで 片っ端から既定のプロパティを排除するのも、ちょっと頭カタイのかな? という思いもチョッピリあったので、 半平太さんの持論は私には新鮮で感じ入るものがありました。
(部外者が横から失礼しました。スミマセン)
(白茶) 2018/02/21(水) 18:48
>「わぁ...ごちゃごちゃ見辛いわ消そ」とか^^;
省略できると分かってて、大量にある時はそう感じますよね。
OfficeTanakaさんは、 「.Valueを全部書く事もない、省略していることが認識できているかが大事」 なんて趣旨のことを書いているんですけどねぇ。
"ネタ帳"さんは、その趣旨のことも書いているが、
「省略しているのは .Valueじゃない、._Defaultプロパティだ。 Valueプロパティを指定しないときにValueプロパティとして扱われるのは、 オブジェクトブラウザから明確な仕様として読み取ることはできません。 経験則としてValueプロパティとして扱われることがもちろん多いですが。」 なんて言ってます。
私としては、「だから何だ」と言いたい。
._Defaultプロパティの仕様が分からないのと同じくらい Valueプロパティの仕様だって知らないじゃないか。
明確に仕様が分かるプロパティなんてどこに在るの? (プログラムをみせて貰える訳じゃなし。まぁ、見せてくれても読み解けないですけど、私レベルでは。)
両者に違いがあるとすれば2点
1.Valueと言う単語が英語の辞書に載っていて、分かった気になれる。 でも英語の辞書はValueプロパティの仕様書じゃない。
2.Valueプロパティを使った経験値が高い。
これは馬鹿にできない。 我ら一般ユーザーにとって、そんな経験が即、仕様とも言える。 いわば「逆算仕様」です。
でも、自分自身でも言ってますよね 「経験則としてValueプロパティとして扱われることがもちろん多い」 それが逆算仕様ってものです。
逆算仕様を活用して何が悪いの? 多かれ、少なかれ誰でもやっていることです。
それにしても表現が微妙ですね。「もちろん多い」って。 じゃ、何が違うのって思います。
多分、何か違うことがあった経験があるんでしょうね? でも、「 な! チャンと.Valueを付ければ旨く行よね」・・・って言う前に .[_Default] を付けても同じくダメになることを確認して欲しいですね。
もしダメにならなかったら、Valueと違うとは言えない、且つ、ダメになった原因が 「省略じゃない何か」のセイと言うことになるので、プロパティの話からズレてしまう。
人に要求するばかりじゃ気が引けるので、"ネタ帳さん"の挙げてくれた「省略するとまずい例」を考えてみた。 ※昔も読んで、それなりに納得していたと思うんですが、こちらも成長しているので、見方もかなり違ってきますね。
Sub 文字列追加1()’省略する例 結果→ A1,A2 には"id"が追加されない Dim rng For Each rng in Range("A1:A2") rng = "id" & rng Next End Sub
Sub 文字列追加2()’省略しない例 結果→ A1,A2 には"id"がチャンと追加される Dim rng For Each rng in Range("A1:A2") rng.Value = "id" & rng.Value Next End Sub
何故、rngをVariant型にしたか不明ですが(その型も使える事はヘルプに書いてあります)、
rng = "id" & rng
このステートメントは、左辺のrngは当たり前のVariant変数になるから セルに"id"がセットされないのは、そんなに不思議に感じないです。
逆算仕様の中でもレベルの低い話ですよね。
さて、自分で出した宿題をやってみます。
Sub 文字列追加3() '左辺に.[_Default]プログラムを追加 結果→ 実行時エラー Dim rng For Each rng In Range("A1:A2") rng.[_Default] = "id" & rng.Value Next End Sub
なんと! 「実行時エラー438 オブジェクトはこのプログラムまたはメソッドをサポートしていません」 となってしまった。
.Value と .[_Default] とは明らかに異なる振舞いと言えます。
でも、既定のプロパティを省略せずチャンと書いたんですから「サポートしていない」はないんじゃない。 既定のプロパティって一体なんだということになります。
そこで、rngをRange型にしてみると、.Valueだろうが、.[_Default] だろうが、省略しようが、 何もトラブりません。
翻ってみれば、rngがVariant型であることが元凶としか思えない。
逆算仕様としては、Variant型に格納したオブジェクト型は、 本来のオブジェクト型と完全にはイコールでない、となりそう。
プロパティの話に直結させなければならない訳でもない。 「頻繁に使うRangeの型くらい合わせましょうよ」とでも言いたくなります。
(半平太) 2018/02/22(木) 14:25
>逆算仕様としては、Variant型に格納したオブジェクト型は、 >本来のオブジェクト型と完全にはイコールでない
非表示のメンバにまではアクセス出来ない ってところでしょうかね。
>プロパティの話に直結させなければならない訳でもない。 >頻繁に使うRangeの型くらい合わせましょうよ」とでも言いたくなります。
そうですね^^;
「省略するとまずい例」を作るには、 この様にちょっと「苦しい」書き方をせざるを得なかった・・・
という事情が垣間見えてしまいます。 「.Value」を省略しない人が、意味も無く「As」を省略することは考えにくいですから
(白茶) 2018/02/22(木) 17:11
> Sub 文字列追加1()’省略する例 結果→ A1,A2 には"id"が追加されない
> 翻ってみれば、rngがVariant型であることが元凶としか思えない。
上記その通りで、
Variant型にRange型を入れてたけど 途中で文字型を放り込もうとした時点でString型に変わった
というお話でしょうね。
Sub test1() Dim rng For Each rng In Range("A1:A2") Debug.Print "1:" & TypeName(rng) 'Rangeだよ rng.Value = "id" & rng.Value 'RangeのValueプロパティに文字列を入れるよ Debug.Print "2:" & TypeName(rng) 'まだRangeだよ
rng = "id" & rng 'Variant型の変数に文字列(右辺が文字列と結合されてるから文字列扱い)を入れるよ Debug.Print "3:" & TypeName(rng) '文字列入れたんだから今はString型だよ rng.Value = "" 'String型にValueなんてプロパティないからエラーだよ Next End Sub
For〜Each〜Nextに使ったからと言って、
Variantの内部の型が確定されるわけでは無い、
のでしょう。
以下と挙動は一緒
Sub test2() Dim rng
Set rng = Range("A1") Debug.Print "1:" & TypeName(rng) 'もちろんRangeだよ rng.Value = "id" & rng.Value 'RangeのValueプロパティに文字列を入れるよ Debug.Print "2:" & TypeName(rng) 'まだRangeだよ
'別処理に変数使いまわしちゃおう rng = "id" & rng 'Variant型の変数に文字列(右辺が文字列と結合されてるから文字列扱い)を入れるよ Debug.Print "3:" & TypeName(rng) '文字列入れたんだから今はString型だよ rng.Value = "" 'String型にValueなんてプロパティないからエラーだよ End Sub
ついでに試したらこんな挙動も
Sub test3() Dim vnt For vnt = 1 To 2 Debug.Print "1:" & TypeName(vnt) 'Integerだよ vnt = "" 'Variant型の変数に文字列を入れるよ Debug.Print "2:" & TypeName(vnt) 'Stringになったよ Next 'For〜Next用の変数が数値型じゃなくなったからエラーだよ End Sub
(ご近所PG) 2018/02/23(金) 11:50
今回の件はValueは付けちゃいけない事例では?
〜〜ヘルプからの抜粋〜〜
Key1 オプション バリアント型 最初の並べ替えフィールドを範囲名 (文字列) または Range オブジェクトで指定し、並べ替える値を特定します。
〜〜抜粋終わり〜〜
見識を深めるために、疑問を提起。
「Rangeオブジェクトの既定のプロパティってValueでしたっけ???」
Sub test()
Range("A3")(3, 5).Select End Sub (まっつわん) 2018/02/23(金) 17:00
ご近所PG さん こんばんは
ご検証いただいたものは、既に考慮していると認識しております。
ご近所PG さん風に書きますと、私の書きたかったことは以下です。
Sub 文字列追加3() '左辺に.[_Default] 結果→ 実行時エラー Dim rng For Each rng In Range("A1:A2") rng.[_Default] = "id" & rng.Value 'Variant型rngは、Range型になっているのでプロパティを書いたよ 'ありゃ? 実行時エラーになっちゃったぞ。 'しかも、サポートしてないなんて言われちゃった '既定のプロパティなのになんでかなぁ
Next End Sub
test3が何の為のテストなのかハッキリ分からないですが、 番外トピと言う理解で・・
> Next 'For〜Next用の変数が数値型じゃなくなったからエラーだよ
そこは、私の経験では 'For〜Next用の変数が「数値・数字」データじゃなくなったからエラーだよ となるハズです。
Sub test3Rev() Dim vnt For vnt = 1 To 2 Debug.Print "1:" & TypeName(vnt) 'Integerだよ vnt = "2" 'Variant型の変数に文字列を入れるよ Debug.Print "2:" & TypeName(vnt) 'Stringになったよ Next 'For〜Next用の変数が文字型になったけど、数字なのでエラーにならないよ End Sub
まっつわんさん こんばんは
>今回の件はValueは付けちゃいけない事例では?
「今回の件」とは、元トピックですか? なら、その通りです。
Rangeオブジェクトのまま処理すべきものを Valueプロパティをつけてしまったと言うことです。
この引っ越しトピでは、元トピックから切り離して、 Rangeオブジェクトを見るや機械的に「.Value」を付けてしまう迄になった風潮に ちょっと茶々をいれているとこです。
簡略に言えば 1..Valueを付けるべきところでも、既定のプロパティ(つまり省略)に任せて何が悪いんだ? 2.そもそも、.Valueを付けるべき場面かどうか、的確に判断できているんでしょうか(一般ユーザーレベルの人は)? あやしーい。 3..Value は 既定のプロパティ.[_Default] と何が違うのか?
>「Rangeオブジェクトの既定のプロパティってValueでしたっけ???」
既定が、.[_Default] であることは、この問題に興味のある人の間では 常識に近くなっていますが、Valueとの違いが非常に分かりにくいです。
なので、Valueが省略されたと言うことで議論してもそんなに頓珍漢な展開にはなりません。
実のところ、.[_Default] プロパティは行列番号を引数に取るプロパティです。(オプション扱い)。 (インテリセンスにもヒントが出ます)
引数を取ると、再びRangeオブジェクトを返して来ることになるんで、その点はValueと明らかに違う部分ですが、 その話を絡めると議論の方向がズレますので、ここでは引数を取らない場合だけで、考えたいと思います。
このtestは、引数を取る場合のサンプルですね? ↓ >Sub test() > Range("A3")(3, 5).Select >End Sub
以前「Range("A3")(3, 5).Select」←こんな書き方あるの? なんて質問がありました。
回答者は、、Range("A3").Cells(3, 5).Select のCellsが省略されたものであり、 可読性を損なわないように省略はしないように、ってなアドバイスをしていました。
私は、(3, 5)はCellsの引数じゃないと言ったんですけど無視されました。 .[_Default] プロパティの引数だよと言えば良かったかもです(多分それでも無視されたでしょうが・・)
(半平太) 2018/02/23(金) 23:40
なるほど、
.[_Default]ってつけてるんだからRangeとして扱えよなんで通らないんだよ、納得。
それを受けての白茶さんの以下の意見と。
> 非表示のメンバにまではアクセス出来ない > ってところでしょうかね。
意図を汲み取り切れておらず失礼しました。
test3はご認識通り、番外編でした。
for〜nextで使ってる変数をループ内で変えるな、
という基本姿勢でプログラムを組んできたけれど
はて、あえてやってみたらどんなことが起こるのかな?
うわ、エラーになった。こわっ。
という思いを伝えんがための内容でしたが、
さらなる事例の提示いただき、なるほど。
数値に出来ないとNGだけど、
VBの暗黙の型変換を通ればOKなんだ。
先に結論として書かれている通り
[As Variant]だから起こりえる問題で
As Range なり As Integer なりで宣言した変数で
for each〜next、for〜nextを記述できる場面なら
型宣言をキッチリすれば起こりえない問題ではありますが、
改めてVBの裏側にあるブラックボックスっぷりを感じられる事例でした。
(ご近所PG) 2018/02/24(土) 10:43
便乗質問かもですが。
Dim r As Range
Set r = Range("A1:A10") r(5, 1) = 10
のr(5, 1)も.[_Default]の省略との認識でいいのでしょうか。
cellsでは無い事は解かるのですが。省略可能なItemとの関連など
ご教示いただければと思いUpしました。
拝見していて、とても勉強になります。
Variant型ってとても便利ですけど、気をつけないといけないのですね。
私のレベルだと、実験して乗り越えるしかないようです。
(隠居じーさん) 2018/02/24(土) 11:27
自動判定のせいで、逆に自動判定の誤判定回避方法を考えなくちゃならない、
とも書いてた人がいたくらいだし
.[_Default]プロパティ
引数なしの場合とありの場合で、返すものが違うのでしょう
Dim t As Variant t = Range("A1:B2").[_Default] Debug.Print TypeName(t)
この場合はVariant()を返す
2行目を
Set t = Range("A1:2").[_Default] と書き換えて実行させると「型が違います」、
1行目を
Dim t As Range と書き換えて実行させると「オブジェクト変数または With ブロック変数が設定されていません」
ということは、引数無しの場合は値しか返さないと思われます
引数ありの場合だと
Debug.Print TypeName(Range("A1:B2").[_Default](1)) Debug.Print Range("A1:B2").[_Default](1).Address
Range $A$1
Debug.Print TypeName(Range("A1:B2").[_Default](2, 2).Item(1, 1)) Debug.Print Range("A1:B2").[_Default](2, 2).Item(1, 1).Address
Range $B$2
Debug.Print TypeName(Range("A1:B2").[_Default](3, 2).Item(1, 1)) Debug.Print Range("A1:B2").[_Default](3, 2).Item(2, 4).Address Debug.Print Range("A1:B2").Cells(3, 2).Item(2, 4).Address Debug.Print Range("A1:B2").Range("B3").Item(2, 4).Address
Range $E$4 $E$4 $E$4
エラーにもならないし、結果も表示されているから
引数ありの場合は「Range」オブジェクトを返すんでしょうね、きっと
これに自動型変換が絡んでくると何がなんだか分からないってなことに
(2u) 2018/02/24(土) 14:28
> Set t = Range("A1:2").[_Default]
Dim t As Variant Set t = Range("A1:B2").[_Default] Debug.Print TypeName(t)
エラーは変わらず。
(2u) 2018/02/24(土) 14:34
Debug.Print Range("A1:B2").[_Default](3, 2).Item(2, 4).Address
解ったような気がします。
暫く。Valueつけたり、つけなかったり。TESTしながら
勉強します。
(隠居じーさん) 2018/02/24(土) 14:57
>のr(5, 1)も.[_Default]の省略との認識でいいのでしょうか。
いいと思います。
>cellsでは無い事は解かるのですが。省略可能なItemとの関連など
「省略可能なItem」ですか? Cellsプロパティのヘルプを読んだんですね?
TVコメンテータ風に言うと「その記事は嘘っぱち」です。
先ずですが、Cellsプロパティは、Range全体のセルを返すものです。
なので、Range("A1:A10") と Range("A1:A10").Cells は同じもんです。 この場合、Cellsを付ける意味が全くありません。(無害ですけど)
※なお、Range("A1:A10").Columns と Range("A1:A10").Columns.Cells なら別ですよ。(念のため) 前者は、大元と異なり、Range型ではあるものの、Columnタイプです。 後者は、大元と同じタイプに戻ります。
さて、Rangeオブジェクトならば、タイプがなんであろうとも プロパティを省略すれば、当然 .[_Default]プロパティが適用されます。
Itemプロパティが省略可能な訳はないです。省略可が2種類あったら、どっちか分からなくなります。
すると、今回の本題と似たような話の展開になります。(以下、Cellsはワザと書込んでいます)
これが → Range("A1:A10").Cells(5,1) これだとして、 → Range("A1:A10").Cells.[_Default](5,1)
これと何が違うの? → Range("A1:A10").Cells.Item(5,1)
もし機能が同じなら、ヘルプの説明が「嘘っぱち」なんて過激に言う必要もないです。 むしろ、一般ユーザーに分かり易く(少しだけ誤魔化して)説明したに過ぎない、と暖かくみることも出来ます。
じゃ、機能が同じなんですか、って聞かれると困ります。
それが分かれば苦労ないです。 逆に、違うならどこが違うんですか? と問いたい。
幾らなんでも、似すぎていませんか?
合理的な推測は、 .[_Default]は、銭湯の番台みたいなものである。
客をみて、引数があれば男湯(Item)に案内する。 無ければ女湯(Value)に案内するだけ(のプログラムである)。
客は直接、男湯に行ってもいいし、女湯に行ってもいい 入る湯殿はさっき案内されるハズだった湯殿(プログラム)と同じである。
(半平太) 2018/02/24(土) 15:37
いや〜あれ〜って暫く考え込んでいました。^^
すっきりしましたです。
ご説明。まだ半分くらいしか理解できて無いかもですが。
熟読して開発時によく留意していきます。
(隠居じーさん) 2018/02/24(土) 16:00
自分はこんな風に解釈しています。的なものを・・・
WindowsやWorkbooks等コレクションには大抵Itemと_Defaultがありますが、 同様に、Rangeは「コレクションとしての性質を持っている」という考え方です。
Rangesコレクションなんてのもありますが、そうじゃなくって、 CellオブジェクトとCellsコレクションってのがあっても良さそうな気がします。
私もVBAやり始めた頃「なんでCellオブジェクトってものがないんだろ?」と疑問に思ったことがあります。 もう、慣れてしまって、それが普通になっちゃいましたが、やっぱ不自然かな? と。
CellsがCellの集合体で、RowsがRowの集合体で、ColumnsがColumnの集合体で でも、 Cellオブジェクトも、Rowオブジェクト、Columnオブジェクトも出てきません。 すべてRangeオブジェクトです。
Rangeオブジェクトを「Cellオブジェクト(架空)のコレクション」だと思えば、_DefaultはItemの方が自然です。 同様に「Rowオブジェクト(架空)のコレクション」だと思ったとしても、やっぱ_DefaultはItemの方が自然です。 では、単一セルのRangeオブジェクトを「Cellオブジェクト(架空)」だと思えば、その_Defaultは・・・
まぁ、Valueが「自然」なのかどうかは、分かりませんが ^^; そんな考え方も出来るのかな? と思った次第です。
(白茶) 2018/02/24(土) 16:50
ちょっと思い出しましたので追記。
>「なんでCellオブジェクトってものがないんだろ?」 と疑問に思った瞬間。
For Each i In Target.??? ←ココを何にするか?
というやつで考えるとしっくりくるかも。 セル単位にイテレートするならCells、行単位ならRows、列単位ならColumnsですね。 でも、変数iを宣言するときは、いずれの場合も As Rangeです。
そん時に「As Cell」とか「As Row」って無いんだ・・・と思ったのでした。 (蛇足スミマセン)
(白茶) 2018/02/24(土) 17:10
>「なんでCellオブジェクトってものがないんだろ?」
私も最初に感じた疑問ですね。 単数か複数か、結構な違いがあります。
普通の変数でも、配列かどうかで取り扱い方法が違いますが、 Valueプロパティも、単セルの場合と、複数セルの場合では挙動が異なります。
・・えーと、ここまで単に「Valueプロパティ」と言って、話を進めたのですが、 プロパティって、大抵、取得と設定がありますよね。
プロパティは名前は同じでも、オブジェクト内のプログラムは別物で、 その点、普通の変数とは全く異なります。
普通の変数に1を入れれば、その変数から値を貰うと、必ず1ですが、 プロパティの方は、1コインを貰って、2コインで保管することもできれば 1コインの残高から3コインにして返させることだって出来ます。
まぁ、常識的にはそんな作りにはしませんけど、 プログラムなので何をしでかすか分からないと言えます。
なので、設定なのか取得なのかを区別しないで考察するのは (今更言い出すのも気が引けますが)ナンセンスかも知れないです。 m(__)m
Value の ヘルプを読むと
> Range.Value(RangeValueDataType) > 指定されたセル範囲の値を表すバリアント型 (Variant) の値を設定します。値の取得および設定が可能です。
> Worksheets("Sheet1").Range("A1").Value = 3.14159
引数(RangeValueDataType)を省略すると
> 指定した Range オブジェクトが空の場合は Empty 値が返されます。 > これを調べるには、IsEmpty 関数を使用します。 > Range オブジェクトに複数のセルが含まれているときは、値の配列が返されます。 > これを調べるには、IsArray 関数を使用します。
と書いてありました。
設定する話なのか、取得する話なのか実に分かりにくいですが、主に取得のことと思われます。 その割には、使用例は設定が重点ぽいので、訳分からないです。
結局どんな類の物(データ?)を与えれば設定できるのか、その詳細は読み取れません。 皆さん、この仕様(?)で、自信もって値を設定するコード書けますか? ・・・てな茶々は止めといてと・・
私の経験則では、以下の種類が与えられるかなと思います(他にあったら教えてください)。 (1)値(単セルのValueプロパティはこちらに分類される)、 (2)値配列(複数セルのValueプロパティはこちらに分類される) (3)オブジェクト(主にRangeオブジェクト)
さて、本題に戻りますが、上の使用例は Worksheets("Sheet1").Range("A1").Value = 3.14159 でしたが、
1.それを(.Valueを省略) Worksheets("Sheet1").Range("A1") = 3.14159 で何か不具合が出たことある方いますか?
2.更に、一般化して Rangeオブジェクト = 上記(1)、(2)、(3) で何か不具合が出たことある方いますか?
3.不具合が出た時、「.Value」を付けたら、不具合が解消できましたか?
上記2では、不具合が起こり得るのですが、上記3が「いいえ」になるなら 少なくとも値を設定するケースでは、.Value省略可能、と言う結論になりますけど。
(半平太) 2018/02/25(日) 14:48
この引っ越しトピでは、元トピックから切り離して、 Rangeオブジェクトを見るや機械的に「.Value」を付けてしまう迄になった風潮に ちょっと茶々をいれているとこです。 簡略に言えば 1..Valueを付けるべきところでも、既定のプロパティ(つまり省略)に任せて何が悪いんだ? 2.そもそも、.Valueを付けるべき場面かどうか、的確に判断できているんでしょうか (一般ユーザーレベルの人は)? あやしーい。 3..Value は 既定のプロパティ.[_Default] と何が違うのか?
なるなる。この手の話は、普通の質問の回答に付随させても、
本題が見えなくなりやすいのでなかなか出来ないんですよね^^;
知識としては結構、本質の部分なんでしょうけど。
質問者の方が、も少し突っ込んでどんどん聞いてくれればいいのですが、
どうしても「期待通り動いた。」で考えることを止めてしまうみたいですね。
なるほど、そうなると、
「ぜったいValueを付けましょう。」という人は、
オブジェクトを指定するところは、
「ぜったいCellsを付けるべき。」とするようにした方がいいということですね^^
既定のプロパティの話しは、
省略されているのは、「.[_Default]」というプロパティなんですね。
で、
引数のある場合はItemプロパティと同じ機能として動き、
引数の無い場合は Valueプロパティとして機能する。
他の場合もあるかもしれないしないかもしれないが
忖度して機能してくれるのが.[_Default]というプロパティと
言う事なんですね^^
> Rangesコレクションなんてのもありますが、そうじゃなくって、
> CellオブジェクトとCellsコレクションってのがあっても良さそうな気がします。
> 「なんでCellオブジェクトってものがないんだろ?」
> CellsがCellの集合体で、RowsがRowの集合体で、ColumnsがColumnの集合体で、でも、
> Cellオブジェクトも、Rowオブジェクト、Columnオブジェクトも出てきません。
> すべてRangeオブジェクトです。
んと、行の集まりも列の集まりもセルの集まりもすべて「セル範囲(=Rangeオブジェクト)」
ですよね?
で、セル範囲には、四つの形態(視点?トリガー?いい言葉が思いつかない^^;)があります。
セルの集まり=Cells
行の集まり=Rows
列の集まり=Columns
矩形の集まり=Areas
なのでセル範囲をどういった視点で見るかをプロパティで指定できる作りになっています。
だから、Cellsオブジェクトというものは定義されてないのだと考えられます。
>のr(5, 1)も.[_Default]の省略との認識でいいのでしょうか。
>cellsでは無い事は解かるのですが。省略可能なItemとの関連など
>ご教示いただければと思いUpしました。
そういう認識でいいと思いますが、
基本的には
r.Item(5,1)
と同意となります。なので、
>Range("A1:B2").[_Default](3, 2).Item(2, 4).Address
こんな記述をするなら敢えて非表示のプロパティを記述しなくても、
Range("A1:B2").Item(3, 2).Item(2, 4).Address
と書けばいいと思います。
では、以上を踏まえて、、、もう少し考察してみましょう^^
以下のコードは実行時エラーとなります。
どこが間違っているでしょうか?
Sub test()
Dim c As Range
For Each c In Range("B3:E5").Rows Debug.Print c.Item(1, 3).Address Next End Sub
(まっつわん) 2018/02/26(月) 14:40
なんか、話がそっぽに行っちゃう感じですね。
私としては、こうなんですけども。 ↓ > 引数を取ると、再びRangeオブジェクトを返して来ることになるんで、その点はValueと明らかに違う部分ですが、 > その話を絡めると議論の方向がズレますので、ここでは引数を取らない場合だけで、考えたいと思います。
まぁ、強制はしませんが・・
(半平太) 2018/02/26(月) 16:07
しかし、.Valueを付けろと言う人が多数だと思っていて、
「こんなことがあるから、付けないとダメなんだ」と言う話を いやと言うほど聞かせられることになると不安(期待?)だったんですけど、 今のところ、そんな気配がないですねぇ。
登場いただくには、まだ機が熟していないですか?
(半平太) 2018/02/26(月) 16:33
しかし、.Valueを付けろと言う人が多数だと思っていて、 そっか、そこなんですね。。。
なんでそういう流れになってたんでしたっけ。。。?
僕的にはそうじゃないとだめというより、意図や意思を明確に書きたいなと。。。
そういわれると、Valueと書かないとだめな事例思いつかないですかね。。。
(まっつわん) 2018/02/26(月) 17:56
For Each r In rr
If Not dic.Exists(r.Value) Then dic.Add r.Value, r End If Next (隠居じーさん) 2018/02/26(月) 18:40
Option Explicit '********************************************************** Sub main() Dim sh01 As Worksheet Dim i As Long, j As Long, rr As Range, r As Range, dic As Object Set sh01 = Worksheets("Sheet1") Set dic = CreateObject("Scripting.Dictionary") j = sh01.Cells(Rows.Count, 1).End(xlUp).Row Set rr = Range("A1:A" & j) For Each r In rr If Not dic.Exists(r.Value) Then dic.Add r.Value, r End If Next For i = 0 To dic.Count - 1 sh01.Cells(i + 1, 2) = dic.Keys()(i) Next Set dic = Nothing Set sh01 = Nothing End Sub
(隠居じーさん) 2018/02/26(月) 18:50
有難うございます。
1. これ、何をしているところですか? 説明をお願いします。 ↓ >sh01.Cells(i + 1, 2) = dic.Keys()(i)
2.あと、Valueの省略はどこでやっていますか?
ここですか? (Yesなら、.Valueを入れたら正常化するかどうかご確認をお願いします) ↓ sh01.Cells(i + 1, 2) = dic.Keys()(i)
(半平太) 2018/02/26(月) 19:17
済みません。 こっちの方は分かりました。m(__)m ↓
> 1. これ、何をしているところですか? 説明をお願いします。 > ↓ > >sh01.Cells(i + 1, 2) = dic.Keys()(i)
具体的にどんな症状なのですか? ↓ >誤作動、若しくはエラー
(半平太) 2018/02/26(月) 19:31
> Set rr = Range("A1:A" & j) ↑ この部分の親が、sh01とも限らない書き方になっていますが、大丈夫ですか?
(半平太) 2018/02/26(月) 20:12
dic.Add r.Value, r End If 上記は通常、成功です。 上記部分でvalueを両方ともつけなければ、全て重複しないと判断され、コピーと同じに For Each r In rr If Not dic.Exists(r) Then dic.Add r.Value, r End If Next の場合に実行時エラー457 このキーは既にコレクションキーに 割り当てられています。
For Each r In rr
If Not dic.Exists(r.Value) Then dic.Add r, r End If Next だと、コピーとおなじになります。
Set rr = sh01.Range("A1:A" & j) 。。。すみませんわすれてました。
にしても
結果はおなじです。
とり急ぎ症状報告まで。
(隠居じーさん) 2018/02/26(月) 21:18
range1.value = range2.value 指定によるセルの値コピーパターン セル C1:E1 の値を C3:F3 (行は変化)にコピーする・・・はず F列を含めているのはわざとです
range の後の指定を色々変えてます
Sub Macro1()
Cells.ClearContents
Range("C1").Value = "test1" Range("D1").Value = "test2" Range("E1").Value = "test3"
Range("A2").Value = "代入テスト1" Range("C3:F3") = Range("C1:E1") Range("C4:F4") = Range("C1:E1").Value
Range("A5").Value = "代入テスト2" Range("C6:F6").[_Default] = Range("C1:E1") Range("C7:F7").Value = Range("C1:E1")
Range("A8").Value = "代入テスト3" Range("C9:F9") = Range("C1:E1").[_Default] Range("C10:F10").Value = Range("C1:E1").[_Default]
Range("A11").Value = "代入テスト4" Range("C12:F12").[_Default] = Range("C1:E1").[_Default] Range("C13:F13").[_Default] = Range("C1:E1").Value
Range("A14").Value = "代入テスト5" Range("C15:F15").[_Default](1, 2) = Range("C1:E1").[_Default] Range("C16:F16").[_Default](1, 3) = Range("C1:E1").Value
Range("A17").Value = "代入テスト6" Range("C18:F18").Cells(1, 2).Value = Range("C1:E1").Cells Range("C19:F19").Cells.Item(1, 3).Value = Range("C1:E1").Cells.Value
Range("A20").Value = "代入テスト7" Range("C21:F21").Cells = Range("C1:E1").Cells Range("C22:F22").Cells = Range("C1:E1").Cells.Value
Range("A23").Value = "代入テスト8" Range("C24:F24").Cells.Value = Range("C1:E1").Cells Range("C25:F25").Cells.Value = Range("C1:E1").Cells.Value
End Sub
で実行した結果ですが、なぜか一部値が表示されないようなんですが・・・自分のところだけ? (2u) 2018/02/27(火) 00:02
2u さんのコード 当方 win10, Excel 2016 でのテスト結果です。
A B C D E F 1 test1 test2 test3 2 代入テスト1 3 4 test1 test2 test3 #N/A 5 代入テスト2 6 7 8 代入テスト3 9 test1 test2 test3 #N/A 10 test1 test2 test3 #N/A 11 代入テスト4 12 test1 test2 test3 #N/A 13 test1 test2 test3 #N/A 14 代入テスト5 15 test1 16 test1 17 代入テスト6 18 19 test1 20 代入テスト7 21 22 test1 test2 test3 #N/A 23 代入テスト8 24 25 test1 test2 test3 #N/A
何かの
参考まで
m(__)m
(隠居じーさん) 2018/02/27(火) 00:48
Sub test001()
Dim Rng As Range Dim v
ActiveSheet.Cells.ClearContents
Set Rng = Range("C1:E1") Rng = Array("test1", "test2", "test3")
If IsArray(Rng) Then MsgBox "配列です" If IsEmpty(Rng) Then MsgBox "空白です"
With Rng.Resize(, 4) .Rows(3) = Rng .Rows(3) = Rng.Value .Rows(3) = Rng v = Rng .Rows(3) = v .Rows(3) = Rng(1) v = Empty .Rows(3) = v End With End Sub
表示されないのはもともと空白のところに、空白を入力しているから、
「表示されない」ように見えるようです。
対象のレンジオブジェクトが複数セルの場合、右辺にValueプロパティを記述していないと、
Variant型のEmpty値と認識されているような挙動にみえます。(結果から想像。)
(まっつわん) 2018/02/27(火) 09:02
(隠居じーさん)さん
私としては、簡単そうな「プロパティの設定」から片付けたかったんですが、 いただいた案件を検討してみます。
これは、Rangeオブジェクトの値の「取得」の問題であるとともに、 「Dicrtionaryオブジェクトのプロパティまたはメソッド」の仕様を どれくらい知っているかの問題でもあります。
前にも言及しましたが、オブジェクトのプロパティやメソッドはプログラムです。 何が仕込まれているか分かったものではありません。
私の"逆算仕様"では、Dicrtionaryオブジェクトはキーとして、 値だけでなくオブジェクトも受け付けます。(下記※をご参照)
なので、単に「r」としてしまうと、それはオブジェクト自体が渡るのであり、 「Valueを付けないRangeだと思ったもの、つまり値」とは別のキーになっています。
試しにrに、.[_Default] を付けてみてください。
For Each r In rr If Not dic.Exists(r.[_Default]) Then dic.Add r.Value, r End If Next
トラブらないですよね?
つまり、rは既定のプロパティを省略したものではないもの(=オブジェクト)であることが言えるとともに、 ここでも .[_Default] は.Value と同等の振舞いをしたと言えると思います。
この問題は「Rangeプロパティの省略しても値が渡せるか否かの話」とは別次元のものです。
オブジェクトで渡すか、値にして渡すか、自分で決めなければしなければならない局面で選択をミスったに過ぎません。
教訓その1(オブジェクトのプロパティやメソッドに引数を与える時) 引数のデータ型が何種類あるのか知っている必要がある。 (知らないなら、調べるしかない。)
仕様が分からないのに、 一つ覚えに .Valueを付ければいいんだと思ったり、逆に、外したっていいんだと思うのは 子供のやり方と同じである。
どちらかが旨く行ったとしても、まぐれの延長でしかないです。また、 両方とも旨く行かなくても本来、驚くことはない現象です。 自分の知らない(しかし当たり前の)ことが起きているだけです。
我ら一般ユーザーは、数あるオブジェクトについて ロクに仕様が分かっていないことを自覚する他ないです。
(※)以前やったDicrtionaryオブジェクトの実験です。
Sub TEST() Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary") Dic(Range("A1")) = "a" Dic(Range("A1")) = "b" Dic(Range("A1")) = "a"
MsgBox Dic.Count '← キーは3個
Dic.RemoveAll
Dim rA As Range
Set rA = Range("A1") Dic(rA) = "a" Dic(rA) = "b" Dic(rA) = "a"
MsgBox Dic.Count '← キーは1個 End Sub
2u さん
ご協力ありがとうござます。
本来、私がやらなければならないテストなのですが(既に一部はやっていますけど)、凄く助かります。
この現象についても、上記「教訓その1」が当てはまります。
また、もっと上の方で述べた内容の具体例でもあります。 ↓ > 普通の変数でも、配列かどうかで取り扱い方法が違いますが、 > Valueプロパティも、単セルの場合と、複数セルの場合では挙動が異なります。
今回、問題が多い方の「複数」のケースが網羅されていて、とても助かります。
実験いただいた結果からも、 明示したValueと 明示した.[_Default] にはまったく差が無いことが確認できます。(不具合であれ、成功であれ)
更に、プロパティの設定側(イコールマークの左側)に限って言えば、 .Value や.[_Default] を書こうが書くまいが、結果(不具合であれ、成功であれ)が同じであることも確認できたと思います。
(半平太) 2018/02/27(火) 09:11
m(__)m
(隠居じーさん) 2018/02/27(火) 10:26
いつ "機が熟す" か分からないので、ここで中締めに入ります。
もしかしたら、それがきっかけで "機が熟す" かも知れませんし・・
今回、色々情報を頂いたお陰で、またまた新しい知識が増えました。 たまには茶々も入れてみるもんです。
まず、基本姿勢としては、まっつわん さんの 「意図や意思を明確に書きたいなと。。」
と言うのが正しいと感じました。当然、Valueを付けるのが正しいケースでは、ですけども。
その上で、面倒と感じる時に.Valueは省略できないの? と言う形で考えてみます。
その前にですが・・・
.[_Default]プロパティは、実コードに書くもんじゃなかったです。 ※テスト目的では別ですけどね。
そのプロパティは、純正Rangeオブジェクトにしか付けられない様です。 このステートメントが、例の「サポートしていない」トラブルになったので分かりました。 ↓ >Range("C19:F19").Cells.Item(1, 3).[_Default]
ItemプロパティはVariant型にRangeオブジェクトを格納したものを返してくる仕様の為です。
では、以下、私の考える省略可能条件です。 ※余り煩雑な場合分けは、逆に面倒になるので、細かい成立条件が必要なものは取り上げません。 ※下の「スカラー」とは、オブジェクトじゃないもの(値や普通の変数)の意味で使用しています。
1. 等号の左辺側にある方は省略可能 2.等号の左辺側がスカラーなら、右辺にあっても省略可能
たった、これだけです。これ以外は危ないです。
それだけでもまずいよ、と言う例がありました教えて下さい。
簡略なサンプルは以下の通りです。
Sub 左辺省略の例() Dim aa
aa = "AA"
Range("A1:A2") = aa '左辺省略 Range("B1:B2") = Range("A1:A2").Value '左辺省略 Range("A1:C2") = Range("A1").Value '左辺省略 End Sub
Sub 右辺省略の例() Dim aa, bb
Range("A1:C2") = [{"A1","B1","C1";"A2","B2","C2";"A3","B3","C3"}]
aa = Range("A1") '右辺省略 bb = Range("A1:C2") '右辺省略 End Sub
(半平太) 2018/02/28(水) 15:25
インフルでぶっ倒れている間に、もー付いてけない世界になっちゃってます〜^^;
自分で言っといてアレですが、Formula系プロパティだって一括取得・設定ができるし、 単一セルと複数セルの取扱の違いについては、本件主題とは切り離して考えるべきだったかも・・・^^;
それはさておき、
Private Sub TestPrint(Arg1, Arg2) Debug.Print Arg1, TypeName(Arg2), VarType(Arg2) End Sub
Sub test() Dim r As Range Set r = Range("A1:B2")
Debug.Print "値なし", "TypeName", "VarType" r.Value = Empty TestPrint "省略", r TestPrint "Value", r.Value TestPrint "_Default", r.[_Default] TestPrint "Formula", r.Formula TestPrint "Text", r.Text TestPrint "Worksheet", r.Worksheet
Debug.Print Debug.Print "A1値あり", "TypeName", "VarType" Range("A1").Value = 1 TestPrint "省略", r TestPrint "Value", r.Value TestPrint "_Default", r.[_Default] TestPrint "Formula", r.Formula TestPrint "Text", r.Text TestPrint "Worksheet", r.Worksheet
End Sub
値なし TypeName VarType ローカルウィンドウの「型」 省略 Range 8204 (Variant/Object/Range) Value Variant() 8204 (Variant/Variant(1 to 2, 1 to 2)) _Default Variant() 8204 (Variant/Variant(1 to 2, 1 to 2)) Formula Variant() 8204 (Variant/Variant(1 to 2, 1 to 2)) Text String 8 (Variant/String) Worksheet Worksheet 9 (Variant/Object/Sheet1)
A1値あり TypeName VarType ローカルウィンドウの「型」 省略 Range 8204 (Variant/Object/Range) Value Variant() 8204 (Variant/Variant(1 to 2, 1 to 2)) _Default Variant() 8204 (Variant/Variant(1 to 2, 1 to 2)) Formula Variant() 8204 (Variant/Variant(1 to 2, 1 to 2)) Text Null 1 (Variant/Null) Worksheet Worksheet 9 (Variant/Object/Sheet1)
Variant型引数に渡したRangeは、Rangeオブジェクトとして格納されはいますが、 Objectであると同時に内部処理形式はバリアント型配列として扱われています。
これを見ると .Valueの省略によって「Rangeが何を渡しているのか」というよりは、 「受け取った側がどの様に扱ってるのか」という問題にも見えてきます。
この捉え方でも、半平太さんからの警鐘?は頷ける考え方ですね。
>> シート上での使用を想定したFunctionプロシージャで、 >> 特に配列を渡す(つもりの)引数をVariant型で表現したりする場合なんかは、 云々と、自分でも書いていますが、 WorksheetFunctionに限らず、純正メソッドの引数がVariant型だったりしたら、 実は「Rangeを求められている」のかもしれないよ?
くらいには構えておいた方が無難なんだろうな。
恐らく多くの場合、どっちでもイケるようにVariant型なんでしょうけど、 ・・・と、そう解釈しているのも、自分の勝手な解釈ですし。
これは気を付けねば・・・
(白茶) 2018/02/28(水) 17:32
> .Valueの省略によって「Rangeが何を渡しているのか」というよりは、 > 「受け取った側がどの様に扱ってるのか」という問題にも見えてきます。
これは、もうその通りでしかないです。
昔、Ichinoseさんにイヤと言うほど説教されました。
オブジェクトがらみの挙動は、引数を貰う側のオブジェクトのプロパティプロシージャが その引数をどう取り扱うか(扱ってくださるか?)に掛かっています。
「値」だけを待っているプロパティ(例:Value)に、オブジェクト型の引数を渡すとどうなるかは 当該プロシージャの(プログラマーの)胸先三寸で決まります。
(1)型違いエラーで突っ返す (2)エラーにはしないが、木で鼻を括るような処理をする。(例:複数セルが来たら、Emptyで返す) (3)値データの積りなのだなと忖度して、チャンと処理してくれる。(例:単セルが来たら、そのValueを返す)
上記(3)の時、当該プロパティプロシージャは、貰ったオブジェクトの既定プロパティを利用して 値を取得することになります。つまり、初めから値が渡るのではなく、救済工程において値化が実現します。
(半平太) 2018/02/28(水) 20:24
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.