[[20101203205934]] 『Range("A1:B3") = Range("D2:E4") で左辺がEmpty』(半平太) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『Range("A1:B3") = Range("D2:E4") で左辺がEmptyになる理由は?』(半平太)

 他所でやっていた議論なんですが、未消化のまま早々と解決マークが入ってしまい、
 (そのセイなのか)その後レスが付かなくなってしまった。

 <valueについて>
http://excelfactory.net/excelboard/excelvba/excel.cgi?mode=all&namber=141625&rev=0

 私も真相が知りたかったので、ここで改めて私の言葉で質問してみます。

 テストコードは後記の通りです。

 現象
 (1) test1を実行すると、Range("A1:B3")にRange("D2:E4")の値がセットされます。
 (2) test2またはtest3を実行すると、Range("A1:B3")にはEmptyがセットされます。

 それは何故か? と云うのが質問の趣旨です。

 <initializing直後>         <test1>の結果
  行 _A_ _B_ _C_ _D_ _E_       行  _A_  _B_  _C_  _D_  _E_ 
   1 a1  b1  c1  DD1 EE1               1  DD2  EE2  c1   DD1  EE1
   2 a2  b2  c2  DD2 EE2   →       2  DD3  EE3  c2   DD2  EE2
   3 a3  b3  c3  DD3 EE3               3  DD4  EE4  c3   DD3  EE3
   4             DD4 EE4               4                 DD4  EE4

                   <test2>および<test3>の結果
                                      行  _A_  _B_  _C_  _D_  _E_
                                       1            c1   DD1  EE1
                                       2            c2   DD2  EE2
                                       3            c3   DD3  EE3
                                       4                 DD4  EE4

 1.test1の結果の見かた
  右辺は Range("D2:E4")オブジェクトであり、値を返す潜在力があるが、
  顕在化している訳ではない。
  しかし、左辺のvariant変数に値が渡っている。これはどの様なメカニズムなのか?

  単に、その様な仕様になっている、と理解するしかないのか?
  (これは、そうだとしても私は納得できる。気が利いているから。)

 2.test2の結果の見かた
  左辺のオブジェクトに右辺のオブジェクトを代入した。
  その様なことはできるとも思えないが、エラーにはならず、
  なぜか、Emptyになってしまった。

  これも(バカになって)、仕様として受け入れるしかないのか?

  常識的なあるべき姿は、両辺ともrangeオブジェクトであり、書式も含めて
  全プロパティが代入される、と云う仕様の方が、リーズナブルと思われる。

  にも関わらず、値が移ったのならまだしも、Emptyになっちゃったでは、
   仕様といってもやりそこなった(バグ)と評価せざるを得ない気がする。

 3.test3の結果の見かた
  左辺がValueプロパティで値を要求しているのに、右辺のオブジェクトを与えようとしている。

  型違いでエラーになるのが順当と思うが、そうはならない。
  それなら、右辺の値をもらうのかな? と思うのだが、Emptyになってしまった。

  右辺の値はEmptyではないから、VALUEプロパティが想定外のRangeオブジェクトを貰って
  パニクってしまい、自オブジェクトの値をEmptyに変えてしまった、と考えるしかない。

  しかし、この結果も納得できるには程遠い。そんな仕様を作る人の顔が見たい。

 一体全体どう理解すべきなのか?
  限りなくバグに近い仕様なのか、はたまた
  リーズナブルな仕様が、たまたま奇異に感じるケースを処理しただけで、
  当然の結果である・・・といえる何かがあるのか?

 'テストコード
 Sub test1()
     Dim val As Variant
     initializing
     val = Range("D2:E4")
     Range("A1:B3") = val
 End Sub

 Sub test2()
     initializing
     Range("A1:B3") = Range("D2:E4")
 End Sub

 Sub test3()
     initializing
     Range("A1:B3").Value = Range("D2:E4")
 End Sub

 Sub initializing() 'テスト用データセット
  Range("A1:C3").Value = [{"a1","b1","c1";"a2","b2","c2";"a3","b3","c3"}]
  Range("D1:e4").Value = [{"DD1","EE1";"DD2","EE2";"DD3","EE3";"DD4","EE4"}]
 End Sub


自己削除
ichinose


 半平太さんの質問に私などがレスして良いものか・・・

 ichinoseさんが消されてしまったのが残念ですが
 憶測で物を言っていいのかわからないので躊躇しながらも・・・

 私なりの納得の仕方といいますか、私見ですが

 Sub test4()
 Dim myRng As Range
 Set myRng = Range("D2:E4")
 Range("A1:B3") = myRng
 End Sub

 こんなイメージじゃないのかな?と。
 RangeオブジェクトにRangeオブジェクトを代入しようとしても
 プロパティがわからないので、何もしない。

 そもそも、これで全てのプロパティがセットされると便利というか
 応用範囲が相当広がるのですが、これに変わる機能が無いなぁと以前から感じてました。

 誤解を招かないようにお願いしますが、あくまで私見です。

 (momo)

 > 半平太さんの質問に私などがレスして良いものか・・・
 私には雲の上の存在の様なお方が何をおっしゃいますやら

 > ichinoseさんが消されてしまったのが残念ですが
 今日、出がけに拝見して成程な、と思ったのですが
 帰ったら、削除されていたので、何か勘違いがあったのかなと思い
 D2:E4にfomulaArrayを入れてみましたところ、
 A1:B3はEmptyにはなりませんでした。(Valueエラーです)
 でも、考えるヒントになりました。

 > Sub test4()
 > Dim myRng As Range
 > Set myRng = Range("D2:E4")
 > Range("A1:B3") = myRng
 > End Sub
 >
 > RangeオブジェクトにRangeオブジェクトを代入しようとしても
 > プロパティがわからないので、何もしない。
 「何もしない」ならまだ解るのですが、A1:B3が「Empty」になってしまうのです。
 つまり、何かしている(少なくとも何かが起こっている)と考えざるを得ません。

 そこでichinoseさんのレスをヒントに、こう考えました。

 Range("A1:B3").Value = myRng の場合
 Valueプロパティは値を要求している。
 にも拘わらず値配列が来なかった。
 処理ルーチンは「無効なデータが来た」、つまりNULLとして処理する。
 NULLなら、セル値ではEmptyになります。

 少し不親切な設計ですが、ふらつきのない仕様として納得できます。

 最後に残ったのが、左辺がValue無しのケースです。
 つまり → Range("A1:B3") = myRng

 ichinoseさんのレスでは、左辺はValueプロパティがあろうが、なかろうが
 同じ様に考えていたようなんですが、何故、そう考えていいのかが今のところ
 分かりません。(現象は同じですけど、それを以って、同じだ、とも言いにくいです)

 「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」と云うのが
 どの掲示板でも、この種の質問に回答者が持ち出した(中途半端な)理由づけ、だったと
 思います。

 (半平太) 2010/12/04 18:57

 > ichinoseさんが消されてしまった
 ご推察のとおり、fomulaArrayでは、説明がつかない事が判明したので
 削除してしまったのですが・・・。私もすぐに出かけてしまったので、
 思考が中断してしまいました。

 で、もう少し色々試してみました。

 Sub test1()
    Range("a1:b2") = [{1,2;3,4}]
    MsgBox "値設定"
    Range("a1") = Range("a2:b2")
    MsgBox IsEmpty(Range("a1"))
 End Sub
 Sub test2()
    Range("a1:b2") = [{1,2;3,4}]
    MsgBox "値設定"
    Range("a1") = Range("a2,b2")
 End Sub

 test1は、セルA1がEmptyになり、test2は、a2の値が入ります。
 単に複数のセル範囲だけではなさそうです。

 Fomulaarrayの予測は外れましたが、

 >左辺はValueプロパティがあろうが、なかろうが
 >同じ様に考えていた
 Value付となしで結果が変わらないことから、
 Rangeオブジェクトが代入(=)の右辺では
 Valueプロパティが既定のプロパティと仮定しています。
 test1,test2も range("a1").value でも結果は同じでした。

 Option Explicit
 Private r_value As Variant
 Property Let value(vl As Variant)
   'この中で vlを精細にチェックして対応している
 End Property

 上記のようなアルゴリズムで何らかの場合わけをしている という想像は、
 未だに反例が認められないので、とりあえずこういう仮説をたてています。

 以上から・・・・、
 test2のようなパターンでは、値を返し、
 test1では、Empty・・・、意図がある仕様ではないか というにおいはしますねえ。

 test1では、emptyを返さなければならない 理由が???ですが、

 ichinose


 例をもう一つ

 Sub test3()
    Range("a1:b2").value = [{1,2;3,4}]
    MsgBox "値設定"
    Range("a1") = Range("a2,a2:b2")
 End Sub

 Sub test4()
    Range("a1:b2").value = [{1,2;3,4}]
    MsgBox "値設定"
    Range("a1") = Range("a2:b2,a2")
 End Sub

 test3は、値を返し、Test4は、Emptyになりました。

 どうやらAreas(1)のセル範囲が複数か否かで判断しているのかなあ・・・。

 因みに
 Range("A1:B3") = Range("D2:E4")
 このコードは、
  A1:B3のすべてのセル範囲にRange("D2:E4")のオブジェクトが代入されているという考えです。
 range("a1")=Range("D2:E4")
 range("b1")=Range("D2:E4")
 range("a2")=Range("D2:E4")
 range("b2")=Range("D2:E4")
 ・
 ・
 

 ichinose


 >どうやらAreas(1)のセル範囲が複数か否かで判断しているのかなあ・・・。
 ちょっとレスが遅れましたが、

 > test1は、セルA1がEmptyになり、test2は、a2の値が入ります。
 > 単に複数のセル範囲だけではなさそうです。
 これについては、別の原理で考えております。

 Areaが複数になったとき、初めの範囲しか処理されない、と云うものです。
 これ → Range("a2,b2")  は、range("A2")だけが処理されます。
 つまり、単数セルの処理と同じ扱いです。

  Sub icTest2()
     Dim rng
     Range("a1:b2") = [{1,2;3,4}]
     MsgBox "値設定"

     For Each rng In Range("a2:b2").Areas
         MsgBox rng.Count   
     Next

     For Each rng In Range("a2,b2").Areas 
         MsgBox rng.Count
     Next
  End Sub

 (半平太) 2010/12/04 20:19

 何となく、RangeのValueプロパティ内でオブジェクトとして、
 複数のセル範囲(areas(1)で)を検出すると、 Emptyを返す というのが大筋ではないでしょうかねえ!!

 スレッドシートコントロール(正確には、Microsoft Office Spreadsheet 10.0)
 をシートに貼り付けて

 Sub test9()
     Range("a1") = _
         ActiveSheet.Spreadsheet1.Worksheets("sheet1").Range("A2:B2")
 End Sub

 これもセルa1は、Emptyになりました。
 この場合、スプレッドシートのRangeとExcelのRangeでは、クラスが違います。
 このようなこともあるのでValueプロパティの引数に
 オブジェクトが指定されたときは、いくつかのチェックの上(複数のオブジェクトが含まれる)で
 このまま既定のプロパティを代入するのは危険だと判断した場合、
 Emptyをセットする
 ということではないでしょうか?

 やっぱり、オブジェクトのプロパティは記述する癖は付けておいた方がよさそうですね

 ichinose 

 単純に

 Sub test1()
 Dim myRng As Range

 Range("A1:B2") = [{1,2;3,4}]
 Set myRng = Range("A2:B2")
 Range("a1:b1").Value = myRng
 End Sub

 Sub test2()
 Dim myRng As Range

 Range("A1:B2") = [{1,2;3,4}]
 Set myRng = Range("A2:B2")
 Range("a1:b1").Value = myRng.Value
 End Sub

 test1がEmptyでtest2が値なので

 >「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」と云うのが
 >どの掲示板でも、この種の質問に回答者が持ち出した(中途半端な)理由づけ、だったと
 >思います。

 これがうなずけちゃいますね。

 まぁでも・・・
 あたかもオブジェクトにオブジェクトを代入するように見えるコード自体がナンセンスかな〜
 と言うのが基本的な事だと思いますので。(これは周知の事ですが)
 オブジェクトとして取り扱うのか、プロパティを扱うのかは明示しておくのが良いですね。

 VBAでは許されても、他の言語では許されない書き方でしょうし
 むしろエラーにならないほうが不思議な書き方ですよね。

 (momo)原因がわからない言い訳です・・・(笑)

 ichinoseさんへ

 > これもセルa1は、Emptyになりました。
 > この場合、スプレッドシートのRangeとExcelのRangeでは、クラスが違います。
 > このようなこともあるのでValueプロパティの引数に
 > オブジェクトが指定されたときは、いくつかのチェックの上(複数のオブジェクトが含まれる)で
 > このまま既定のプロパティを代入するのは危険だと判断した場合、
 > Emptyをセットする

 危険と判断するのは、左右どちら側とお考えですか?
 左辺側(値の設定サイド)ですか、右辺側(値の取得サイド)ですか? それとも・・・?

 いままで左辺側の話として考えていたのですが、
 今回は、右辺側に移ってしまったのかな、と云う感じがします。
 (始めから、右辺側だったのでしょうか?)

 momoさんへ

 > これがうなずけちゃいますね。
 私の書いた文章が2つの意味を持っている為、どの部分がうなずけるのか分かりません。

 「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」と云う理由は、
 下例のtest1とtest2が違う結果になることには意味がありますが、
 test2とtest3が同じ結果になる理由にはなりにくいです。
 (左辺だって、違うプロパティのハズですから)

 ※ 無理に云えない事はないですが、なんかご都合主義的に感じます。
    なので、(中途半端な理由)とカッコ書きしたのですけども。

 Sub test1() '値がセットされる
     initializing
     Range("A1:B3").Value = Range("D2:E4").Value
 End Sub

 Sub test2()  'Emptyがセットされる
     initializing
     Range("A1:B3").Value = Range("D2:E4")
 End Sub

 Sub test3()  'Emptyがセットされる
     initializing
     Range("A1:B3") = Range("D2:E4")
 End Sub

 Sub initializing() 'テスト用データセット
  Range("A1:C3").Value = [{"a1","b1","c1";"a2","b2","c2";"a3","b3","c3"}]
  Range("D1:e4").Value = [{"DD1","EE1";"DD2","EE2";"DD3","EE3";"DD4","EE4"}]
 End Sub

 (半平太) 2010/12/05 09:28

 >危険と判断するのは、左右どちら側とお考えですか?
 左辺ですよ!!
 私は、Property letの話しかしていませんので・・・。
 >Valueプロパティは、RangeオブジェクトのDefalutプロパティではない
 私は、
 Valueプロパティは、Rangeオブジェクトの既定のプロパティだ という考えから
 話をしています。

 この一連の話から、
 >Valueプロパティは、RangeオブジェクトのDefalutプロパティではない
 という証拠らしい結果は、何もないですよね?

 Emptyを設定しているのも 左辺valueプロパティ内でそういう設定をしているのだ
 という想像です。

 ichinose


 > 左辺ですよ!!
 そうだとしますと、スプレッドシートは別クラスの事であり、
 左辺(別クラス)がどのようなプロパティ処理をしていようとも、
 次元が異なる事象なのではありませんか?

 > この一連の話から、
 >> Valueプロパティは、RangeオブジェクトのDefalutプロパティではない
 > という証拠らしい結果は、何もないですよね?

 これについては、周知の事実として進めていいであろう、くらいにしか認識しておりませんでした。
 誰かが反論していたのを見たことがありません。ichinoseさんが始めてです。
 ※実のところ、目にした回答が右辺についてだけ云ったのかどうか定かではないです。
  (右辺だけとすると、ご都合主義だなぁと感じるのですが)

  DefaultプロパティはItemだと思っています。

 「Worksheet.Cells プロパティ」についてのマイクロソフトの説明書きを読むと、

 > 現在使用されているセルだけでなく、ワークシートのすべてのセルを表すRange オブジェクト
 > を取得します。値の取得のみ可能です。 
 > Item プロパティは、Range オブジェクトの既定のプロパティであるため、
 > Cells キーワードの直後に行や列のインデックスを指定できます。
 > 詳細については、Item プロパティを参照してください。

 となっていて、Rangeオブジェクトの既定のプロパティはItemであるとハッキリ書かれています。

 それで、ヘルプでItemを見ると

 > オブジェクトを返すプロパティです。指定した範囲からのオフセットの範囲 (Range オブジェクト) を返します。
 > 値の取得および設定が可能です。バリアント型 (Variant) の値を使用します。

 となっています。

 RangeオブジェクトからRangeオブジェクトを返すプロパティとは何のこっちゃと思いますが、
 とにかくValueプロパティでないことは確かだと思います。

 (半平太) 2010/12/05 11:06

 >DefaultプロパティはItemだと思っています。
 そう書いてあるらしいですね、でも、実質的には、Valueプロパティと同じ値が返るのではないですか?

http://vba-range-cells.seesaa.net/article/158086978.html

 >左辺(別クラス)がどのようなプロパティ処理をしていようとも、
 >次元が異なる事象なのではありませんか?

 Property Let value(vl as variant)
 'この中で指定されたパラメータ(つまり、Vl)が何であるかを判断しているのだと思いますよ
 VBAで言えば、TypenameとかVartype 等(もっと精細関数が別言語ではあるかもしれません)を使って
 Vlが何であるかを調べて その値よって、結果を変えているということです。
 end property

 上記で

 obj.value=range("a2:b2")

 と指定すれば vlは、range("a2:b2")というRangeオブジェクトを参照するはずです
 

 適当なクラスをVBAで作成して、同じような処理がされれば、良いですよね

 VBAでは、既定のプロパティって簡単には、作成できなかったと思いますが、
 方法もあったように思います(プロパティってきちんと書くべきという考えなので
 要らないからいままで調べてなかったけど)。

 ちょっと調べてみます。

 ichinose
 

 中途半端なmomoです(^^;
 >「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」
 が、正当なように見えてしまう。そんな現象なんですねぇ〜と
 単純が頭が思考してます。

 元々あんまり追求しないタイプなので、こういう事に参加するのも珍しいのですが。

 私自身は、「なるべく」正しく書こうね〜くらいです。
 というか、本当に正しくコードを書いてる人なんてほとんど見たことがありません。

 Dim r as range だって、本当は Dim r as excel.range なんでしょうし
 (オブジェクトブラウザで見ると。ですね)

 Cells(1) なんてのも、本当は Cells.item(1) なんでしょうし・・・

 私の現在の環境と知識では皆様以上に調べる方法が思いつかないのでこの辺で^^

 進展を楽しみにしています。
 (momo)

 新規ブックにて、以下の手順でコードを作成してください。

 クラスモジュールを作成してください(クラス名は、既定のClass1)

 Class1のモジュールに

 '========================================================
 Option Explicit
 Private r_value As Variant
 '========================================================
 Public Property Get value() As Variant
    value = r_value
 End Property
 '========================================================
 Public Property Let value(vl As Variant)
    Dim obj As Object
    Dim cnt As Long
    r_value = Empty
    If TypeName(vl) = "Range" Then
       If vl.Areas(1).Count = 1 Then
          r_value = vl.Areas(1)
       End If
    Else
       If valchk(vl) Then
          r_value = vl
       End If
    End If
 End Property
 '========================================================
 Private Function valchk(vl As Variant) As Boolean
    Dim obj As Object
    Dim cnt As Long
    On Error Resume Next
    valchk = False
    Set obj = vl
    If Err.Number <> 0 Then
       valchk = True
    Else
       cnt = vl.Count
       If cnt <= 1 Then valchk = True
    End If
 End Function

 ご覧のとおり、Valueというプロパティしかないクラスです。

 Property Getでは、
 値の保存先の r_value をそのまま返しただけのコードです。

 Property Letでは、パラメータvlの型等を調べてそれによって、
 違った値をr_valueに設定しています。
 では、どんな条件かというと・・・、

 vlがオブジェクトではない場合、無条件に値をr_valueに設定します。

 vlがオブジェクトの場合
 特にRangeオブジェクトの場合、
   vl.areas(1).count が1の場合、r_valueにvl.areas(1)の既定のプロパティ値を設定します。
   それ以外は、Emptyを設定

 vlがRange以外のオブジェクトの場合
   Countプロパティをチェックし、1以下(Countプロパティがない場合も可)ならば、
    r_valueに、対象オブジェクトの既定のプロパティを設定します。

   Countが、2以上の場合は、Emptyを設定します。

 仕様は、以上です。

 標準モジュールに

 '===============================================================
 Option Explicit
 Sub test1()
    Dim cls As New Class1
    Dim aa As New Class1
    Dim bb As Variant
    aa.value = Array(1, 2, 3, 4)
    cls.value = aa.value
    MsgBox "aa.value = Array(1, 2, 3, 4)" & vbCrLf & "cls.value = aa.value" & _
           "を実行した結果、 cls.value の型は " & TypeName(cls.value)
    For Each bb In cls.value
       MsgBox "配列要素は  " & bb
    Next
    Range("a1").value = 123
    MsgBox "セルA1に123を設定しました"
    cls.value = Range("a1").value
    MsgBox " cls.value = Range(""a1"").value を実行した結果、cls.Valueは、 " & TypeName(cls.value) & "型で 値は、 " & cls.value
    cls.value = Range("a1")
    MsgBox " cls.value = Range(""a1"") を実行した結果、cls.Valueは、 " & TypeName(cls.value) & "型で 値は、 " & cls.value
    cls.value = 5
    MsgBox " cls.value = 5 を実行した結果、cls.Valueは、 " & TypeName(cls.value) & "型で 値は、 " & cls.value
    cls.value = Range("a1:a5")
    MsgBox " cls.value = Range(""a1:a5"") を実行した結果、cls.Valueは、 " & TypeName(cls.value) & "型で 値は、 " & cls.value
 End Sub
 '==================================================================
 Sub test2()
    Dim cls As New Class1
    Dim aa As New Class1
    Dim bb As Variant
    Dim g0 As Long
    Dim myarray As Variant
    aa = Array(1, 2, 3, 4)
    cls = aa
    MsgBox "aa = Array(1, 2, 3, 4)" & vbCrLf & "cls = aa" & _
           "を実行した結果、 cls.valueの型は " & TypeName(cls.value)
    myarray = cls
    For g0 = LBound(myarray) To UBound(myarray)
       MsgBox " 配列要素は   " & myarray(g0)
    Next
    Range("a1").value = 123
    MsgBox "セルA1に123を設定しました"
    cls = Range("a1")
    MsgBox " cls = Range(""a1"") を実行した結果、clsは、 " & TypeName(cls.value) & "型で 値は、 " & cls
    cls = Range("a1")
    MsgBox " cls = Range(""a1"") を実行した結果、clsは、 " & TypeName(cls.value) & "型で 値は、 " & cls
    cls = 5
    MsgBox " cls = 5 を実行した結果、cls.Valueは、 " & TypeName(cls.value) & "型で 値は、 " & cls
    cls = Range("a1:a5")
    MsgBox " cls = Range(""a1:a5"") を実行した結果、clsは、 " & TypeName(cls.value) & "型で 値は、 " & cls
 End Sub

 このままだとValueプロパティは、Class1の既定のプロパティではないので、

 test1は、正常に作動しますが、test2は、
 aa = Array(1, 2, 3, 4)  'ここでエラーになります。

でも、test1の実行だけでもValueプロパティ内で右辺のデータの型によって
設定する値を変える事が出来ることは理解できると思います。

 次投稿にて、Valueの既定のプロパティへの設定方法とtest2の実行

 ichinose

  


 前回投稿コードのあるブックを一度保存してください。

http://d.hatena.ne.jp/cartooh/20090718/1247926819

 ↑これに倣って、Valueプロパティを既定のプロパティに設定します。

 プロジェクトエクスプローラにて、
 前投稿のClass1を選択してください
 「右クリック」-----「Class1の解放」をクリックしてください。
 「Class1」をエクスポートするか否かの確認メッセージが表示されますから、
 はい でエクスポートします。

 適当なフォルダにClass1.cls として、保存してください。

 メモ帳などで保存したClass1.cls 開いてください。

 VERSION 1.0 CLASS
 BEGIN
  MultiUse = -1  'True
 END
 Attribute VB_Name = "Class1"
 Attribute VB_GlobalNameSpace = False
 Attribute VB_Creatable = False
 Attribute VB_PredeclaredId = False
 Attribute VB_Exposed = False
 Option Explicit
 Private r_value As Variant
 Public Property Get value() As Variant
    value = r_value
 End Property
 Public Property Let value(vl As Variant)
    Dim obj As Object
    Dim cnt As Long
    r_value = Empty
    If TypeName(vl) = "Range" Then
       If vl.Areas(1).Count = 1 Then
          r_value = vl.Areas(1)
       End If
    Else
       If valchk(vl) Then
          r_value = vl
       End If
    End If
 End Property 
 ・
 ・
 ・

 と表示されているはずです。

 property get value()

 Property let value(・・)

 内に

  Attribute value.VB_UserMemId = 0

 という1行を追加し、

 Public Property Get value() As Variant
 Attribute value.VB_UserMemId = 0    ←追加
    value = r_value
 End Property
 Public Property Let value(vl As Variant)
 Attribute value.VB_UserMemId = 0   ←追加 ←以下は実際には削除です
    Dim obj As Object
    Dim cnt As Long
    r_value = Empty
    If TypeName(vl) = "Range" Then
       If vl.Areas(1).Count = 1 Then
          r_value = vl.Areas(1)
       End If
    Else
       If valchk(vl) Then
          r_value = vl
       End If
    End If
 End Property
  

 Class1.clsを上書き保存をしてください。

 VBEに戻り、 プロジェクトエクスプローラにて、
 当該ブックを選択した状態で

 「右クリック」-----「ファイルのインポート」にて、修正したClass1.cls
 をインポートしてください。

 ブックを上書き保存してください。

 これで Valueプロパティの既定のプロパティ化ができたはずです。

 test2を実行してみてください。

 Valueプロパティを付けた場合と付けない場合で違いを比べてください。
 本物のValueプロパティはもっと複雑なんでしょうが・・・。

 これの結果から、Valueプロパティ内で与えられたデータによって
 処理を分ける という可能性は否定できないと思います。

 実際には、中を見てみないとわからない というのも事実ですが。

 尚、既定のプロパティ化は、Excel2002で確認しました。

 ichinose


 momoさんへ

 > Cells(1) なんてのも、本当は Cells.item(1) なんでしょうし・・・
 ちゃんとプロパティを書けと云っている人はドキドキもんですね ^^
 まぁ、なんらかの正当化理由が付くと思いますけども。

 > 進展を楽しみにしています。
 私としてはそろそろ幕引きしようかと思っていたのですけど、
 ichinoseさんが力作を作られている様だったんで、、、

 ichinoseさんへ
  お手数をお掛けして恐縮です。

  こんなスケルトンがあると、ちょっとしたことやるとき助かりますね。
  ・・と云っても、クラスだとかPropetyプロシージャなんて滅多に作らないですけど。

  正直いいまして、ichinoseさんが証明しようとしていることについて行けていないです。

 > でも、test1の実行だけでもValueプロパティ内で右辺の
 > データの型によって設定する値を変える事が出来ることは理解できると思います。 

  私が、「ご都合主義」だと云った為にこれを証明しなければ、と云う事でしょうか?

  JAVAをかじっていますので、シグネチャーによって処理内容が如何様にも
  変わり得る、と云うことは私も承知しております。

  しかし、可能であることと、そうしなければならないこととは違います。

  まぁ、私が問題点なのか、疑問点なのか、単なる感想なのか分からないものを
  だらだら書いたセイで焦点をボカしてしまった観はあります。

  そこで、今まで展開してきた内容も加味して、疑問点を再度まとめてみます。
  (細かいことは省略します)

 疑問1:以下のコードでvalにRangeオブジェクトの値配列が渡される理由は何か?
        Dim val As Variant
        val = Range("D2:E4")

   右辺はValueプロパティがつかないRangeオブジェクトであり、
   何故そのようなことが起こり得たのか疑問である。
   考えられる理由としては、
    (1) 左辺が変数の場合、仕様として値配列が渡されるようになっている。
     (2) 既定のプロパティItemの機能として、値配列が返されるから、
       左辺の変数はあるがままに値配列を受け取ったにすぎない。

   ※ 2番目の理由が正しいとすると、次の疑問点と矛盾することになる。

 疑問2:以下のコードで、左辺のRangeオブジェクトにEmptyが設定されるのは何故か?
        Range("A1:B3").Value = Range("D2:E4")
  
   少なくとも、右辺は値配列を渡していない。
   左辺のValueプロパティがRangeオブジェクトを貰ったとき、
   独自仕様に基づいてEmptyをセットした(のであろう)。

   常識的には、エラーになるか、何もしないか、右辺の値配列を渡すかだが、
   何ゆえ、Empty(配列?)を設定する仕様なのか?

   技術的には問題ないとしても、その仕様に意味を感じない。
   「そうなるのも無理ないね、いや当然だ」と言える何かが欲しい。

   巷間「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」と云う
   理由が上げられることがあるが、これは右辺について述べられたことと考えられるが、
   既定のItemプロパティなら値取得も出来るのではなかったか? 
   そのギャップを埋めるものが欲しい。
   現実には左辺に値を渡していないらしいので、結果と辻褄は合うが、
     じゃ何を渡しているのか、これも説明が不足している。

 ※ 折角、労作をいただいたので何回か走らせ、中身も見ましましたが、
   何を証明しようとしているのか分からなかったので、眺めたと云う方が近いです

   すこし、気になったのは、Variant変数を多用されていることです。
   私の知りたい事からすると、すこし不安に思いました。
   上述しましたとおり、バリアント変数をアダプターにすれば、
   値配列がスムーズに流れてしまいますので、 Rangeオブジェクトの
   既定プロパティはどんなデータを作っているのか観察するのが
   難しくなりそうな気がします。
   もっとも、変数なしでどう観察すればいいのか、と云うジレンマがあります。

 ※ 現時点で、私は、既定プロパティを作る事には興味ありません。
    面白いなとは思いましたが、使い道が分かりません。

 (半平太) 2010/12/06 00:21

 こんにちは〜
 いつもお世話になってます m(_ _)m

 スレッドの本題(←内容については、ただただ へぇ〜と感心するばかりで ずっとROMさせて
  もらってました ^^)からは少し外れますが、 
  Itemプロパティについてちょっと気になったので、雑文書かせてください。

 >> 詳細については、Item プロパティを参照してください。
 > となっていて、Rangeオブジェクトの既定のプロパティはItemであるとハッキリ書かれています。
 > それで、ヘルプでItemを見ると
 >> オブジェクトを返すプロパティです。
 >>   指定した範囲からのオフセットの範囲 (Range オブジェクト) を返します。
 >>   値の取得および設定が可能です。バリアント型 (Variant) の値を使用します。
 > となっています。
 > RangeオブジェクトからRangeオブジェクトを返すプロパティとは何のこっちゃと思いますが、
  ↑
 同感です。
 ヘルプの説明が分かりにくいと言われますが、このItemプロパティの説明など最たるモノですね

 「Item」をヘルプで検索すると、3つあるようです。
  ひとつは [VBAの コレクションオブジェクトの Itemメソッド]のヘルプで
 > Item メソッドはコレクションの既定メソッドなので、次に示す 2 行のコードの意味は同じです。
 >    Print MyCollection(1)
 >    Print MyCollection.Item(1)
 という例が上がっています。

 2つ目は「Excelの Item プロパティ」で、ヘルプでそのページにジャンプしますと、実に沢山の
 Itemプロパティをもつオブジェクトが挙がっています。いわく、
  ・Areas、Filters、HPageBreaks ...オブジェクトのItemプロパティ
  ・Borders オブジェクトの Item プロパティ
  ・Dialogs オブジェクトの Item プロパティ
  ・Errors オブジェクトの Item プロパティ
  など(他にも挙がってますが)、これらに共通する構文は
 >      expression.Item(Index)
 という書式であることです。
 それに対して、Range オブジェクトの Item プロパティ の構文は
  expression.Item(RowIndex, ColumnIndex)
 となっています。(ColumnIndexのほうは省略可)
  例として
  Range.Item(1) は範囲の左上端のセルを返します。Range.Item(2) は左上端のセルの右側のセルを返します。

 3つめは Officeの「Itemプロパティ」です。
 CommandBarsオブジェクトとか WebPageFonts オブジェクトとか(他にも沢山)挙がってます。

 異なるクラスのItemプロパティがもつ共通点はそれらの親オブジェクトが集合(コレクション)
 であり、Itemプロパティは集合内の個々の要素(メンバ)を指定するのに使われているということです。
 よくWorksheets(1) とか Worksheets("Sheet1") と記述しますが、ご承知のように
 これ Worksheets.Item(1) また Worksheets.Item("Sheet1") という構文の簡略表記なんですよね
 ワークシートコレクション内の1番目のシート、ワークシートコレクション内の"Sheet1"というメンバ
 という意味なんですよね。
 Worksheets(1).Cells(1)も同じです.
 Worksheets(1).Cells というとき、.Cellsプロパティで Worksheets(1)内の「すべてのセルの集合」を
 取得しているわけです。じゃ、(1)は何かと言うと、「すべてのセルの集合」内の最初の要素 .Item(1)
 の(1) であるわけです。
 Cellsプロパティは Rangeオブジェクトにたいしても使用できます。
 Range("A1:B3").Cells と書くと、Range("A1:B3")という範囲内の「すべてのセルの集合」を表現して
 ますが、Range("A1:B3")ですでにセルの集合ですから、Worksheets(1).Cellsのように、どうしても
 必要なものでなく、普通は使われません。Range("A1:B3")という範囲の特定の単一セルを指定する
 ときに、Itemプロパティを使います。例 Range("A1:B3").Item(1,4) は [D1]セルのことですし、
 Range("B1:B100").Item(200) といえば[B200]セルのことですよね.
 先程の例 Range("A1:B3").Item(1,4) を Range("A1:B3").Cells(1,4) と表記するひとがいらっしゃ
 いますが、これ Range("A1:B3").Cells.Item(1,4) の簡略表記なんです。先ほど言いましたように
 Range("A1:B3").Cells という表現は「範囲のなかのすべてのセル(の集合)」ということですから、
 RangeオブジェクトにCellsプロパティを修飾するのはやや冗長なわけで、そんなもの省略して
 Range("A1:B3").Item(1,4) と書いたほうが「範囲内の単一メンバ」を指定するのにItemプロパティ
 の機能を使って指定していることが分かりやすいと思います。
 Columns(2) も Columns.Item(2) が省略されたものですね。Excel2003までなら 256列ある列のコレ
 クションのうちの2番目の単一列ということです。
 Range("A1:B3").Item(1,4) は[A1:B3]という範囲内を飛び出しています。Rangeオブジェクトだけでは
 ないでしょうか? Itemプロパティを使ってコレクションの実メンバの範囲外まで指定できるのは?
 だらだらと長くなりましたが、Itemプロパティは一般的にあるコレクションのメンバを指定するための
 プロパティ名として使われ、Rangeオブジェクトの、またCellsコレクションのItemプロパティの機能も
 他のItemプロパティと同じように、セルコレクションの個々の要素を指示するものとしてある、という
 ことだと思います。

 > Itemの機能として、値配列が返されるから、

 ということではないと思いました次第です。

   (kanabun) 2010/12/06(月) 02:03


 私が書いたコードは、例として、既定のプロパティであるValueというプロパティを作成し、

 cls.value=range(“a2:b2”)
 cls=range(“a2:b2”)

 が同じ結果になること
それから、
 cls.value=range(“a2:b2”).value
 cls.value=range(“a2:b2”)

 では、Valueプロパティ内で受け取るデータの型がまるで違うことを申し上げたかったのですが。

 >可能であることと、そうしなければならないこととは違います。
 これは、そのとおりです。
 よって、
 >emptyを返さなければならない 理由が???ですが、
 と最初のほうで書いています。エラーにすればよいという選択肢もありますから・・・。

 ただ、
 range(“a1”).value=range(“a1,a2:b2”)  ではきちんと値を返し、
 range(“a1”).value=range(“a2:b2,a1”) ではEmpty値を返すような徹底ぶり?を
 見ていると、仕様なんだろうなあ

 という想像はしています。
 中身が見えないので、これが本当のところはわかりません。

 *   疑問1について

 Dim val As Variant

  val = Range("D2:E4")

 と
 val= Range("D2:E4").value  が同じ結果を返すことから、

 >(2) 既定のプロパティItemの機能として、値配列が返されるから、

  >      左辺の変数はあるがままに値配列を受け取ったにすぎない。
 実質、Valueプロパティの値を受け取ったという解釈です

 *  疑問2について
 >少なくとも、右辺は値配列を渡していない。
 Range("A1:B3").Value = Range("D2:E4")
 この記述では、左辺のValueプロパティ内では、Range("D2:E4")をRangeオブジェクトと
 認識しているということですよね!!
 ↑これは、パラメータ渡ししている Proerty Letを見ると、わかります。
 これを明らかにするClass1の例でもあったのですが・・・。

 >常識的には、エラーになるか、何もしないか、右辺の値配列を渡すかだが、
 >  何ゆえ、Empty(配列?)を設定する仕様なのか?

 これの理由は、???です。

 Range("A1").Value = Range("D2:E4")
 この式でもemptyになることから、
 単一セルのValueプロパティに複数のセルを表す式を許していないことから、
 Range("A1:B3").Value = Range("D2:E4")
 ↑この式は、
 Range("A1:B3").Value = Range("D2:E4").Value 
 とは左辺のValue側の受け取り方が違い

 Range("A1:B3")の個々のセルのValueプロパティにRange("D2:E4")、
 この複数のセル範囲を含むオブジェクトを設定する
 と解釈しているので、"A1:B3"のそれぞれのValueプロパティに配列を埋め込むでは
 リソース的に問題があるからと没 という解釈はできます。

 Range("A1").Value = Range("D2:E4")
 この式がemptyになる現象は、Excel2000から確認しています(それ以下は確認していませんが)。
 仕様考案時は、単一セルのValueに配列は考えられないが、
 将来は あり得るかもしれない。
 ということで敢えてエラーにせず、Emptyにしていた なんて想像もできます。

 Emptyという仕様にした理由は、想像の域はでません。

 ここが一番の問題なら、一連の確認から、仕様に見えるが、理由はわからない

 という見解です。

 >巷間「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」と云う
 >理由が上げられることがあるが、
 MS社の記述があるから、itemなんでしょうねえ

 >Dim val As Variant

  >val = Range("D2:E4")
 >と
 >val= Range("D2:E4").value

 でも、この例などは、実質Valueと同じものが返っている・・・。
 ここの説明が見当たらない?

 >じゃ何を渡しているのか、これも説明が不足している。
 繰り返しになりますが、左辺のValue側では、オブジェクトととして解釈している
 ということです。Valueというプロシジャーに対し、
 パラメータ渡しをしているのですから、Range("D2:E4")を引数にしたなら、
 オブジェクトとして、渡してもらわないと困ります。スタックには
 Range("D2:E4")の参照が入るはずですが・・・・。その前にインスタンスも作成して・・。
 ここまでなら、Emptyにする仕様の理由に比べたら、納得しやすいと思いますが・・・。

 >現時点で、私は、既定プロパティを作る事には興味ありません。
 これは、あくまでも既定のプロパティを定義してクラスを作成し、
 プロパティを指定した時としない時の違い(あるいは同じ)を明確にしたかっただけです。
 >プロパティは、書くべきという考えなので要らない
 と申し上げたとおり、私も私が作成するオブジェクトには、必要はないです

 ichinose


 追伸

 ご存知かもしれませんが、
 ActiveXControlのTextboxでも既定のプロパティの指定時と省略時では、ちょっと
 違う現象になります。

 仮にSheet1上に貼り付けたTextbox1を例に取ると
 Sub test()
    With Worksheets("sheet1")
       .TextBox1.Value = 123
       .Range("a1").Value = .TextBox1
       MsgBox TypeName(.Range("a1").Value)
       .Range("b1").Value = .TextBox1.Value
       MsgBox TypeName(.Range("b1").Value)
    End With
 End Sub

 A1,B1共に値が設定されますが、A1は、文字列 B1は、数値として設定されます。

 それにしても、

 range("a1:b2")=range("a2:b2")

 私は、プロパティを付けない事は、ほとんどないので気が付かったのですが、
 結構、付けない方もいますよね?
 よく今まで、この問題がでませんでしたねえ

 Excel2000でも確認されたのに・・・。

 ichinose


 もう一つ例

 Sub test3()
    Dim cls As New Class1
    cls.value = Array(1, 2, 3, 4)
    Range("a2").value = cls.value
    MsgBox Range("a2").value
 End Sub
 Sub test4()
    Dim cls As New Class1
    cls.value = Array(1, 2, 3, 4)
    Range("a2").value = cls
    MsgBox Range("a2").value
 End Sub

 例題として作成したClass1(既定のプロパティ付)で
 test3,test4の結果が違いました。

 test4では、Emptyが返ります。
 やっぱり、既定のプロパティが配列か否かを見ているのかなあ

 ichinose


 面白い検証が沢山見られてうれしいです。

 >私は、プロパティを付けない事は、ほとんどないので気が付かったのですが、
 >結構、付けない方もいますよね?
 >よく今まで、この問題がでませんでしたねえ

 本当にそう思います。
 ただ、掲示板を見ているとValue=Valueとする人はプロパティを付ける事が多く、
 そもそもプロパティを書かない人はCopyでPasteSpetialの人が多いのが理由ですかね?

 半平太さん
 >私としてはそろそろ幕引きしようかと思っていたのですけど、
 私は充分ためになりました。ありがとうございます。

 (momo)

 またまた横道ですみません m(_ _)m

 そういえば、こんな記事もありましたね
 「Excelのバグ」
http://blog.officetanaka.com/
 参照URL  http://support.microsoft.com/kb/191176/ja

   (kanabun)


 kanabun さん レス有難うございます。

 Itemプロパティの考え方がよく分かりました。

 > Range("A1:B3").Item(1,4) と書いたほうが「範囲内の単一メンバ」を指定するのにItemプロパティ
 > の機能を使って指定していることが分かりやすいと思います。
 この書き方には納得です。しかし、無意識に冗長版をやってしまいそうな予感があります。(^^ゞ

 >> Itemの機能として、値配列が返されるから、
 > ということではないと思いました次第です。
 左辺が何の時でしょうか?(疑問1に対してはどの様なお考えですか?)

 > 「Excelのバグ」
 ぶったまげモノですね。
 これで、Microsoftの言い分が「仕様」ですから2度びっくりです。

 皆、バグのことを平気で仕様なんて云う様になる訳だ。(Microsoftのファンでもないのに)

 ichinoseさん
  私が「1」考えている間に、「10」ぐらい考えられるのですね。 
  とてもついて行けそうにありません。オタオタしております。

 > 私が書いたコードは、例として、既定のプロパティであるValueというプロパティを作成し、
 > cls.value=range(“a2:b2”)
 > cls=range(“a2:b2”)
 > が同じ結果になること
 これについては、現在時点では、
   Rangeオブジェクトが単独なら、Itemプロパティ省略型のオブジェクトとなる(つまり親オブジェクトそのもの)。
   等号の左辺に置かれると、同上オブジェクトの「既定の値受取りプロパティ」が作動する。具体的には
   Itemプロパティ(Let側)で、おそらくValueプロパティ(Let側)を模したか、下請けにした機能を持っているのであろう。
 と理解することにします。

 等号の右辺に置かれたケースが問題として残っています。
 例のItemのヘルプ記述→『値の取得および設定が可能です。』
 一体、どんなシーンで値の取得って行われるのかさっぱり分からなくなります。
 左辺にだけ適用するのも気が引けます。
 でも、右辺はRangeオブジェクトである公算が高く、暗礁に乗り上げた格好です。
 もしかして、左辺が変数の時だけなんですかね? それだと辻褄合うとも云えます。

 > cls.value=range(“a2:b2”).value
 > cls.value=range(“a2:b2”)
 > では、Valueプロパティ内で受け取るデータの型がまるで違うこと
 これについては、始めから理論上あり得ることと理解しております。
 ちょっと「ご都合主義」を強調し過ぎてしまいました。<(_ _)>

 > range(“a1”).value=range(“a1,a2:b2”)  ではきちんと値を返し、
 > range(“a1”).value=range(“a2:b2,a1”) ではEmpty値を返すような徹底ぶり?を
 > 見ていると、仕様なんだろうなあ
 > という想像はしています。
 まずは「状況証拠」ですね。

 > Range("A1").Value = Range("D2:E4")
 > この式がemptyになる現象は、Excel2000から確認しています(それ以下は確認していませんが)。
 実験してみますと
  Excel97は、同じ様にEmptyになります。
  Excel95は、D2の値になります。

 ついでにXL95で配列の実験をしてみました。
  Range("A1:B3") = Range("D2:E4").Value  → 左辺全セルが、D2の単一値で埋まります
  Range("A1:B3") = Range("D2:E4")        → 左辺全セルが、D2の単一値で埋まります
  Range("A1:B3").Value = Range("D2:E4")  → 左辺全セルが、D2の単一値で埋まります

 ここら辺りに、Empty導入に至った源流があるかも知れません。
 D2をとるかEmptyをとるか、なんてレベルのことなら、甲乙つけがたいと云うより、
 ブービー/メーカつけがたしです。

 > >巷間「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない」と云う
 > >理由が上げられることがあるが、
 >> MS社の記述があるから、itemなんでしょうねえ
 そうなんでしょうけど、この理由は「だから何なの?」と云うところがハッキリしません。
 いつも、ここで終わっているんですよ。

 まぁ、訊く人も初級者が多いから、突っ込む手段がなく、解決にして終わらすしか
 ないのかもです。プロパティを省略した負い目もあることだし。。。。

 でも、突っ込めば、その先は「仕様だ」と云う絶壁しかないかも知れません。

 >> 現時点で、私は、既定プロパティを作る事には興味ありません。
 > これは、あくまでも既定のプロパティを定義してクラスを作成し、
 > プロパティを指定した時としない時の違い(あるいは同じ)を明確にしたかっただけです。
 成程です。大変失礼いたしました。
 検証する目的で、スンナリこんな事が出来る人がうらやましいです。

 > ご存知かもしれませんが、
 > ActiveXControlのTextboxでも既定のプロパティの指定時と省略時では、ちょっと
 > 違う現象になります。
 全然知らなかったです。興味深いです。

 >range("a1:b2")=range("a2:b2")
 >私は、プロパティを付けない事は、ほとんどないので気が付かったのですが、
 >結構、付けない方もいますよね?
 >よく今まで、この問題がでませんでしたねえ
 通常は、コピー先が空白なので、Emptyにされたのに気付かず、
 ただ、データが移動してくれないと云う悩みになり、
 上級者のアドバイスで .value指定で解決!となっていたからではないでしょうか?

 > もう一つ例
 >
 > Sub test3()
 >    Dim cls As New Class1
 >    cls.value = Array(1, 2, 3, 4)
 >    Range("a2").value = cls.value
 >    MsgBox Range("a2").value
 > End Sub
 > Sub test4()
 >    Dim cls As New Class1
 >    cls.value = Array(1, 2, 3, 4)
 >    Range("a2").value = cls
 >    MsgBox Range("a2").value
 > End Sub
 >
 > 例題として作成したClass1(既定のプロパティ付)で
 > test3,test4の結果が違いました。
 >
 > test4では、Emptyが返ります。
 > やっぱり、既定のプロパティが配列か否かを見ているのかなあ
 この実験の評価の仕方がよく分かりません。

 ここでは、既定のプロパティ(Value)か、そのプロパティ(Value)の明示かの違いであり、
 本題では、既定のプロパティ(Item)か、別のプロパティの明示(Value)かの違いなので
 私には、同じ問題かどうか不明です。

 しかし、同じプロパティなのに、省略するかしないかで差が出たと云う意味では、
 clsのケースの方が驚きが大きい気がします。

 とりあえず、能(脳)力が追いついていないので、今日の検討はここまでにさせていただきます。

 (半平太) 2010/12/07 00:42

 ちょっと整理しましょう

 dim a as variant
 a=range("a1:b1")   '1
 a=range("a1:b1").value  
 >もしかして、左辺が変数の時だけなんですかね? それだと辻褄合うとも云えます。
 これもし、既定のプロパティがValueプロパティである と定義されていたなら
 これは、問題ない。

 range("a2")=range("a1:b1")

 これもセルA2の既定のプロパティValue側では、
 range("a1:b1")は、rangeオブジェクトとして認識し、処理される

 ということは理解できる でよいですか?

 が、実際の定義は、Rangeオブジェクトの既定のプロパティは、itemとあるのだから、
 納得できない個所が多々ある。

 ということでよいですか?

 更に既定のプロパティがValueであるならば、

 >Range("A1:B3") = Range("D2:E4") で左辺がEmptyになる理由は?
 そもそものこの現象も、右辺のValueプロパティが配列の場合、
 左辺のValueプロパティにオブジェクトそのものを指定すると

 例1
 range("a1")=range("a2:b2")

 例2
 > Sub test4()
 >    Dim cls As New Class1
 >    cls.value = Array(1, 2, 3, 4)
      Range("a2") = cls
 >    MsgBox Range("a2").value
 > End Sub

 このとき、左辺側にEmptyが設定されるは、仕様というなら 
 それはそれで納得できるでよいのですか?

 私は、これなら、ほぼ晴れてしまうのです。

 が、既定のプロパティは、Valueではなく、Itemプロパティだ。
 だから説明ができない。

 このItemプロパティのメカニズムが??? 結局、問題がここに到達すると思うのですが
 いかがですか?

 そうすると、Helpの説明不足を強く訴えたいなあ・・・。

 >ここでは、既定のプロパティ(Value)か、そのプロパティ(Value)の明示かの違いであり、

 これは、clsオブジェクトを使って、既定のプロパティに配列を指定した時、
 Range("a1").value=cls  でEmptyが返るのだから
 (引数にオブジェクトを指定すると既定のプロパティを見に行き、
 それが配列だとEmpty返す)、

 range("a1").value=range("a2:b2")
 これもrange("a2:b2")というオブジェクトを引数に指定しているので、
 既定のプロパティを調査し、過程は不明だが、結果として、Valueプロパティを調べて
 配列だから、Emptyを返している。 と考えられるのではないか

 よって、最終的には、RangeのValueの引数がオブジェクトの場合、
 既定のプロパティの実態が配列か否かでemptyを設定している ということを
 申し上げたかったのです。
 実際には、Rangeオブジェクト場合、Areas(1)の既定のプロパティまで調査している
 ので、他のオブジェクトとは、場合わけしている可能性もありますが・・・。

 ここでも既定のプロパティItemからValueの値にまで到達する過程は
 説明ができません。

 Itemの疑問に関しては、更に記述したいことがあるのですが、
 半平太さんと、どこまでなら理解できる等という共通認識点を確認しないと
 何分、私、頭はあまりよくないのでこのままだと論点がわからなくなってしまいそうです

 >本題では、既定のプロパティ(Item)か、別のプロパティの明示(Value)かの違い
 本題だと思っていませんでした。これは、問題の過程ででてきた疑問点だと
 思っていました。

 上記が問題なら、
 「Rangeオブジェクトの既定のプロパティItemの詳細とValueプロパティとの関係」

 等という表題で別スレッドにしたいのですが・・・。

 ichinose


 >ちょっと整理しましょう
 >
 > dim a as variant
 > a=range("a1:b1")   '1
 > a=range("a1:b1").value  
 > >もしかして、左辺が変数の時だけなんですかね? それだと辻褄合うとも云えます。
 > これもし、既定のプロパティがValueプロパティである と定義されていたなら
 > これは、問題ない。
 問題ないことになります。

 > range("a2")=range("a1:b1")
 > これもセルA2の既定のプロパティValue側では、
 > range("a1:b1")は、rangeオブジェクトとして認識し、処理される
 > ということは理解できる でよいですか?
 理解できます。

 > が、実際の定義は、Rangeオブジェクトの既定のプロパティは、itemとあるのだから、
 > 納得できない個所が多々ある。
 > ということでよいですか?
 今までの流れはそうなのですが、現時点では「納得できない個所は」多くないです。

 > 更に既定のプロパティがValueであるならば、
 > >Range("A1:B3") = Range("D2:E4") で左辺がEmptyになる理由は?
 > そもそものこの現象も、右辺のValueプロパティが配列の場合、
 > 左辺のValueプロパティにオブジェクトそのものを指定すると

 > 例1
 > range("a1")=range("a2:b2")
 >
 > 例2
 > > Sub test4()
 > >    Dim cls As New Class1
 > >    cls.value = Array(1, 2, 3, 4)
 >      Range("a2") = cls
 > >    MsgBox Range("a2").value
 > > End Sub
 >
 > このとき、左辺側にEmptyが設定されるは、仕様というなら 
 > それはそれで納得できるでよいのですか?
 XL95当時、右辺の第一要素を左辺の全てのセルに埋め込んでいた仕様を
 XL97以降、(気を利かせたつもりで)Emptyで埋める事に変更した。
 五十歩百歩の変更と云えそうですが「仕様」の改定が行われたと
 考えることにします。
 (この部分だけが少し不安ですが、結論は「仕様」とします)

 > が、既定のプロパティは、Valueではなく、Itemプロパティだ。
 > だから説明ができない。
 > このItemプロパティのメカニズムが??? 結局、問題がここに到達すると思うのですが
 > いかがですか?
 いえ、質問開始時点では、右辺にあるRangeオブジェクトは、既定のプロパティ(Item)に従って
 「値」か「オブジェクト」のどちらかを一種類を返すハズ、と考えていたのですが、
 現時点では、左辺の種類によってそれは決定されるとの考えに変わりました。

 すなわち、
  左辺に変数があるなら「値(の取得)」、それ以外なら「rangeオブジェクト」となる。
   左辺が変数なら値を欲しているのであり、Rangeオブジェクトから値を取得して渡す。
   左辺がRangeオブジェクトとかの処理工場つきのものなら、左辺の工場内で処理すれば
   いいのでオブジェクトのまま渡す。

  左辺に置かれた場合は、右辺に何が来ようとも「値の設定」機能のみになる。
   左辺に工場があるので、何が来ようとも仕様に従って値を設定する。

  等号が関係ないときはRangeオブジェクトとなる。
   これは普通に、各種メンバーを使って活用すればよい。

 以上の3形態を理解することで、Itemプロパティに関するヘルプの説明に問題は
 なかったと考えます。

 >>ここでは、既定のプロパティ(Value)か、そのプロパティ(Value)の明示かの違いであり、
 >> 本題では、既定のプロパティ(Item)か、別のプロパティの明示(Value)かの違いなので
 >> 私には、同じ問題かどうか不明です。
 単に、私にはどんな意味があるのか何も分からない、と云いたかったのですが、
 折角、労作のコードでテストして頂いているのに、何の反応も出来ないのでは悪いと思い、
 無理して書いた分析で、あまり意味はありません。(^^ゞ

 > これは、clsオブジェクトを使って、既定のプロパティに配列を指定した時、
 > Range("a1").value=cls  でEmptyが返るのだから
 > (引数にオブジェクトを指定すると既定のプロパティを見に行き、
 > それが配列だとEmpty返す)、
 >
 > range("a1").value=range("a2:b2")
 > これもrange("a2:b2")というオブジェクトを引数に指定しているので、
 > 既定のプロパティを調査し、過程は不明だが、結果として、Valueプロパティを調べて
 > 配列だから、Emptyを返している。 と考えられるのではないか
 >
 > よって、最終的には、RangeのValueの引数がオブジェクトの場合、
 > 既定のプロパティの実態が配列か否かでemptyを設定している ということを
 > 申し上げたかったのです。
 改めて、趣旨をご説明いただくと、一部理解し、一部別の不安が生じています。

 ・・と云いますのは、上の方でItemプロパティについての私なりの理解を書きましたが、
 これは、clsにも適用される(されて欲しい)と考えています。

 右辺に置かれた時は、Rangeオブジェクトは既定のプロパティ(Item)でもRangeオブジェクトになります。
 一方、clsの場合、既定のプロパティはValueで、右辺は値になったと考えられます。
 (ステップ実行した限りでは、Valueプロパティの処理が入っています)

 つまり、Range("a1").value=cls ではオブジェクトを渡さないハズだ、と云うことです。
 もし、それが否定されるなら、これを否定しなければなりません。
                ↓
 「Valueプロパティは、RangeオブジェクトのDefalutプロパティではない(それはItemプロパティである)」

 まぁ、私としては否定されても構いませんが、余りにもいままでそれが通用していたものですから。。。

 しかし、否定するとなると
 「(デフォルトプロパティなんて関係ない)。 そのまんまオブジェクトが渡っているよ。」
 と云うアドバイスでなければいけない気がします。

 > Itemの疑問に関しては、更に記述したいことがあるのですが、
 > 半平太さんと、どこまでなら理解できる等という共通認識点を確認しないと
 私としては、Itemプロパティの理解はほとんど終わっております。

 問題点も最後に生じたもの以外残っておりません。つまり、

 「左辺がRangeオブジェクトの場合、右辺がオブジェクトなら
  そのままオブジェクトが渡される。Defaultプロパティなんて関係ない」

 そう考えて良いかどうかだけです。

 > >本題では、既定のプロパティ(Item)か、別のプロパティの明示(Value)かの違い
 > 本題だと思っていませんでした。これは、問題の過程ででてきた疑問点だと
 > 思っていました。
  表現が不適切でした。上述しました通り、無理に書いた内容です。
 「本題で取り上げているケースでは」と云う意味であって「本題」ではありません。

 (半平太) 2010/12/07 12:16

 済みません、ichinoseさんのご説明を読み違いした様です。

 明日、もう一度考え直してみます。

 (半平太) 2010/12/08 00:32

 Itemプロパティの理解を以下に変更することで、ichinoseさんとほぼ同じになるかと思います。

   左辺に変数があるなら「値(の取得)」、それ以外なら「(親)rangeオブジェクト」のままとなる。
    左辺が変数なら値を欲しているのであり、Rangeオブジェクトから値を取得して渡す。
    左辺がRangeオブジェクトとかの処理工場つきのものなら、左辺の工場内で処理すれば
    いいので(親)オブジェクトのまま渡す。

   左辺に置かれた場合は、右辺に何が来ようとも「値の設定」機能のみになる。
    自前工場があるので、何が来ようとも仕様に従って値を設定する。
    渡されたものがオブジェクトである場合、その既定プロパティを処理対象とする。

   等号が関係ないときはRangeオブジェクトとなる。
    これは普通に、各種メンバーを使って活用すればよい。

 ※  しっかし、既定のプロパティは、右辺において単独に意味するのではなく、
   左辺のオブジェクトに渡されてから、考慮されるとは思ってもいなかったです。
    でも、実のところ、既定のプロパティを持っちゃったら、
   どうやってもオブジェクト自体を渡せなくなっちゃうな―
   と懸念しておりましたので、ホッとしたところもあります。

 ichinose さん お手間をとらせて申し訳ありませんでした。
 これで、本トピックは解決とさせていただきます。
 大変有難うございました。

 momoさん、kanabunさん 色々ご意見をいただき有難うございました。
 私としては、当初の認識から相当離れたところで決着することになったので、
 本当にこれでいいのか余り自信もないですが、面白い見解を持つことが出来たと
 思っています。将来、実力が上がったらまた再検討できればいいなとも思っています。
 参考になるようなことがあればまたお聞かせください。

 (半平太) 2010/12/08 01:25

 > ※  しっかし、既定のプロパティは、右辺において単独に意味するのではなく、
 >  左辺のオブジェクトに渡されてから、考慮されるとは思ってもいなかったです。
 >どうやってもオブジェクト自体を渡せなくなっちゃうな―
 ですよね、何をどうするかは、左辺のProperty Let 側で判断するから、
 オブジェクトを引数にしたら、オブジェクトを渡してくれなきゃねえ。
 大きい違いは、ここだったのでしょうか?

 私もこのご質問で色々考えさせられました。
 私もRangeの既定プロパティは、Itemという記述は、CellsプロパティのHelpで何度か見ていますが、
 実質、Valueプロパティでないか? 又、そうとらえていて、大きい問題がなかったので
 その認識だけがのこっていました。
 よって、itemとValueの関係をきちんと検証しないまま、今日に至っていたのです。

 今回のご質問だって、Rangeの既定のプロパティがValueだと定義されていれば、
 私には、解釈上、何の問題もなくなってきた話になりました
 (Emptyになる現象などは、新発見でしたが)。

 今回のご質問の過程で、「Rangeの既定プロパティは、Item」というご指摘を受け、
 あー、そうだった。でも、ここでも実質Valueじゃんで、解決しようと思っていたのですが・・・。

 ここのところ、あるテレビCMが私の頭のなかで回っていました。
 どこの予備校だったかなあ(東進かなあ)、
 その予備校の講師陣の代表選手が一言二言コメントをしていくCMです。
 今までも流れていたのかもしれませんが、我が家でも子供がその年齢にきたので
 目に止まったのかもしれません。
 最初は、その講師陣の一人に綺麗なおねえさんがいて、
 「基礎の基礎が怖いってこと・・・」と言っているコメントばかり
 気になっていたのですが(おねえちゃんかわいいし)、綺麗なのは何度もみていると
 飽きてきて、次に目にとまったのがサングラスの髭のおじさん
 (おじさんってたって、私よりは若い)。

 「定義がちょっとでも曖昧になってくると、途中でまちがってくる」、
 そのおじさんの↑この言葉がこのご質問を考えている中でよく頭の中によぎってきました。

 私は、Rangeオブジェクトの既定のプロパティItemとValueプロパティの関係を
 曖昧にしているなあ・・・、と思い知らされました。

 ここがきちんと理解できると、今回の現象もまた違った解釈になるかもしれません。

 ということで、近日中に今度は私が別スレッドにて質問をしますので、
 半平太さん、よろしくお願いします。
 momoさん、kanabunさん もよろしくお願いします。

 ichinose


 私的には結論云々よりも、楽しませて頂きました。

 Let・・・なるほど、当たり前のようで意識しませんね。
 普通にコードを書いていると、右辺のプロパティで左辺に与えるものが変わりますものね。

 他にも同様な事があるのかもなぁ?と思うと
 やっぱりプロパティは「なるべく」正確に書く。が基本と再認識です。
 基本的にはこれさえ守れば問題はそうそう出てこないはずですし。

 >ということで、近日中に今度は私が別スレッドにて質問をしますので、
 >半平太さん、よろしくお願いします。
 >momoさん、kanabunさん もよろしくお願いします。
 ichinoseさんからの質問などに私が・・・
 プレッシャーを感じつつ、楽しみでもあります。

 今回はありがとうございました。
 (momo)

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.