none
基本クラスにあるメソッドの引数の型は変更可能なのでしょうか? RRS feed

  • 質問

  • クラスを継承しオーバーライド可能なプロパティやメソッドがあるとき、その戻り値の型や引数の型を変更して隠ぺいすることは可能なのでしょうか?

    例としては、こういったことです。

    public class ColumnHeaderEx : ColumnHeader {
    }

    としたとき、

    public class ColumnHeaderCollectionEx : ListView.ColumnHeaderCollection {
      public void AddRange(ColumnHeaderEx[] values) {
        base.AddRange((ColumnHeader[])values);
      }
    
      public override void AddRange(ColumnHeader[] values) {
        base.AddRange(values);
      }
    }

    ColumnHeaderCollection にある AddRange メソッド(下)を、AddRange メソッド(上)に入れ替えてしまうというようなことです。

    先日の質問のListViewのColumnsとItemsにプロパティを追加する方法(下にURLあり)で拡張したListViewItem、それを参考に組んだColumnHeaderを、デザイン画面のプロパティウィンドウから追加したとき、

    this.listViewEx1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                this.columnHeaderEx1});

    という風になってしまって、この部分だけを見たとき、Nameに設定した値次第では、拡張したColumnHeaderなのか、拡張前のColumnHeaderなのか判断できなくなってしまうように感じました。

    それを回避するためには、どうもAddRange メソッドを用意する必要があるようで用意はしたのですが、引数の型が違うので隠ぺいはムリなようで、2つを共存させる方法しかないのかなぁ?って疑問に思いました。

    このままでも正常に動作するので何の問題もないのですが、Nameの値に関係なく拡張したColumnHeaderだと分かるようにするために、わざわざ2つある状態にしないといけないのか疑問で、1つにできないのか質問をさせてもらいました。

    何となくムリという答えが想像できるのですが、回答を頂けたらと思います。

    (ListViewのColumnsとItemsにプロパティを追加する方法)
    http://social.msdn.microsoft.com/Forums/ja-JP/51212d42-32d9-4d06-b246-88f7de3fd7ba/listviewcolumnsitems



    • 編集済み miwa3125 2013年10月29日 6:49
    2013年10月29日 6:47

すべての返信

  • new キーワードで実現できるかな。

    http://msdn.microsoft.com/ja-jp/library/435f1dw2(v=vs.90).aspx

    2013年10月29日 7:02
  • このままでも正常に動作するので何の問題もないのですが、Nameの値に関係なく拡張したColumnHeaderだと分かるようにするために、わざわざ2つある状態にしないといけないのか疑問で、1つにできないのか質問をさせてもらいました。

    何となくムリという答えが想像できるのですが、回答を頂けたらと思います。

    無理です。一応、overrideした側のメソッドに対し、BrowsableAttribute及びEditorBrowsableAttributeを指定することで、Visual Studio IDE上での補完候補から隠すことはできますし、ObsolateAttributeを指定することで呼び出さないようコンパイル時に警告を出力することもできますが、これらは呼び出しを禁止するものではありません。

    それを行ったとしてもまだ穴があります。

    ListView.ColumnHeaderCollection columns = this.listViewEx1.Columns;
    columns.AddRange(new[]{new ColumnHeader()});

    というコードが書けてしまいますし、その際には親クラスであるListView.ColumnHeaderCollectionのAddRange()が呼び出せてしまいますし、そこで受け取る引数はColumnHeaderEx配列ではなくColumnHeader配列となります。実行時にColumnHeaderExでなくColumnHeaderを渡されることを防ぐことはできません。

    # だから先のスレッドでは拡張メソッドでの機能追加を提案したのですが…。

    galacoさんへ:
    メソッド引数の型が異なる以上、overrideされることはなくoverloadとして扱われます。ですのでoverrideを回避するnewキーワードは無意味です。

    2013年10月29日 7:48
  • ああ、デザイナーで登録するんですね。それじゃ new ではだめですね。済みません。

    2013年10月29日 7:56
  • このままでも正常に動作するので何の問題もないのですが、Nameの値に関係なく拡張したColumnHeaderだと分かるようにするために、わざわざ2つある状態にしないといけないのか疑問で、1つにできないのか質問をさせてもらいました。

    前のスレッドをちゃんと読んでいないんですが、掲載されたコードだけ読んでいると、単純にoverrideしたAddRangeは要らないんじゃ・・・?

    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2013年10月29日 8:17
    モデレータ
  • newでも無駄なことは知ってます。

    ほかに方法があるのかなぁ?って思っただけなんです。

    2013年10月29日 12:19
  • AddRangeを新たに作らなくてイイことは分かってます。

    質問にも書いたように、ほかの人が利用したときに、あのままだと拡張前のものが追加されたと勘違いしてしまう可能性を考え、その回避策として拡張後のものが追加されたと見て分かるようにAddRangeの追加を考えたんです。

    public class ColumnHeaderCollectionEx : ListView.ColumnHeaderCollection {   public void AddRange(ColumnHeaderEx[] values) {     base.AddRange((ColumnHeader[])values);   }   new public void AddRange(ColumnHeader[] values) { ←属性をつける場合のみnewで用意する。
      base.AddRange(values);   } }

    このようにしておけば、

    this.listView1Ex.Columns.AddRange(new WindowsFormsApplication1.ColumnHeaderEx[] {
                this.columnHeaderEx1});

    というようなコードに変わることを確認済みなので。。。

    もし、ColumnHeaderExのNameをcolumnHeader1のように手動で設定をする人がいたとき、教えて頂いた状態のままでは、

    this.listViewEx1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                this.columnHeader1});

    という状態になってしまって、この一ヵ所だけを見たら、拡張済みのColumnHeaderExが追加されているのに、拡張前のColumnHeaderが追加されていると勘違いしてしまうかもしれないと思いませんか?

    NameをcolumnHeader1のように手動で設定しても、

    this.listViewEx1.Columns.AddRange(new WindowsFormsApplication1.ColumnHeaderEx[] {
                this.columnHeader1});

    となるように、AddRangeの追加を考えました。

    AddRange(ColumnHeaderEx[] values)を用意したとしたら、AddRange(ColumnHeader[] values)は不要と言えば不要ですよね?

    なので、なくすことが可能ならなくしたいし、無理ならこのまま2つがある状態にしておくつもりです。

    実際にアプリを作った人と、そのアプリを改編する人が変わったりした場合や、時間が経過して忘れてしまったという時にも、拡張済みのコレクションだと一目で分かるようにしたいだけです。





    • 編集済み miwa3125 2013年10月29日 13:26
    2013年10月29日 12:49
  • このままでも正常に動作するので何の問題もないのですが、Nameの値に関係なく拡張したColumnHeaderだと分かるようにするために、わざわざ2つある状態にしないといけないのか疑問で、1つにできないのか質問をさせてもらいました。

    何となくムリという答えが想像できるのですが、回答を頂けたらと思います。

    無理です。一応、overrideした側のメソッドに対し、BrowsableAttribute及びEditorBrowsableAttributeを指定することで、Visual Studio IDE上での補完候補から隠すことはできますし、ObsolateAttributeを指定することで呼び出さないようコンパイル時に警告を出力することもできますが、これらは呼び出しを禁止するものではありません。

    それを行ったとしてもまだ穴があります。

    ListView.ColumnHeaderCollection columns = this.listViewEx1.Columns;
    columns.AddRange(new[]{new ColumnHeader()});

    というコードが書けてしまいますし、その際には親クラスであるListView.ColumnHeaderCollectionのAddRange()が呼び出せてしまいますし、そこで受け取る引数はColumnHeaderEx配列ではなくColumnHeader配列となります。実行時にColumnHeaderExでなくColumnHeaderを渡されることを防ぐことはできません。

    # だから先のスレッドでは拡張メソッドでの機能追加を提案したのですが…。

    galacoさんへ:
    メソッド引数の型が異なる以上、overrideされることはなくoverloadとして扱われます。ですのでoverrideを回避するnewキーワードは無意味です。


    ただ、コードだけを見たとき、あの方法で追加したのでは、拡張前のものが追加されたと勘違いする人もいるかもしれないということも考えて、その回避策としてわざわざAddRangeを追加する方法を考えてみただけです。

    そして、引数の型違いだけでAddRangeが2つある状態のままでも十分だけど、片方が不要と言えば不要だからなくせるならなくしたいと思っての質問です。

    • 編集済み 星 睦美 2013年10月30日 0:20 技術的な話題に戻すために一部内容を削除させていただきました。
    2013年10月29日 13:13
  • フォーラム オペレーターの星 睦美です。

    質問の内容に話題をしぼりたいと思いましたので私のほうでスレッドの一部を削除させていただきました。
    投稿いただいた方には申し訳ありません。

    miwa3125 さん、
    「コードだけを見たとき、あの方法で追加したのでは、拡張前のものが追加されたと勘違いする人もいるかもしれないということも考えて、その回避策としてわざわざAddRangeを追加する方法を考えてみた」

    コードだけで処理の意図を完全に伝えるのは難しいですよね。必要であれば、処理に関するコメントをコードに残すことはどうでしょうか?

    今回は複数の回答者からの技術的なアドバイスがありますので、目的の機能を実現するための参考にしていただければと思います。


    フォーラム オペレーター 星 睦美 - MSDN Community Support


    • 編集済み 星 睦美 2013年10月30日 0:45 修正
    2013年10月30日 0:44
  • フォーラム オペレーターの星 睦美です。

    質問の内容に話題をしぼりたいと思いましたので私のほうでスレッドの一部を削除させていただきました。
    投稿いただいた方には申し訳ありません。

    miwa3125 さん、
    「コードだけを見たとき、あの方法で追加したのでは、拡張前のものが追加されたと勘違いする人もいるかもしれないということも考えて、その回避策としてわざわざAddRangeを追加する方法を考えてみた」

    コードだけで処理の意図を完全に伝えるのは難しいですよね。必要であれば、処理に関するコメントをコードに残すことはどうでしょうか?

    今回は複数の回答者からの技術的なアドバイスがありますので、目的の機能を実現するための参考にしていただければと思います。


    フォーラム オペレーター 星 睦美 - MSDN Community Support

    私が作る分には、コメントを追加することは可能です。

    ですが、完成している状態のListViewExというDLLを配布した際、このDLLを利用してListViewExを利用した人(私以外の利用者)が、時間が経過しても勘違いしないようにコメントを追加なんてできますか?

    プロパティウィンドウで変更したときに、コメントも一緒に追加されるという方法があるのでしたら、その方法を選びたいと思います。

    そうすれば、新たに追加する必要もなく私の手間も省けるし、誰が使った時にでもそのコメントを読めば、ColumnHeaderExやListViewItemExが追加されていて、拡張で増えたプロパティも使えると判断できると思うので。。。

    [追記]

    もう一点。

    このListViewExのコードは、将来的に公開を予定しています。

    前回の質問で最後に指摘されたリスクに関する注意点について理解をしていただければ、制限なく利用可能にする予定です。

    なので、そのコードを利用して、独自のプロパティの追加やコードの編集を済ませたDLLの配布をされることも考えられます。

    第三者によって提供されたDLLの場合、追加されてたものの勘違いが起こった際のことが心配です。

    公開したコードを利用して作ったListViewでも、同じようにコメントが出なければ、勘違いによる問い合わせへの対応が必要になってしまいます。

    『この部分は勘違い防止用にコメントを出力させていますので、改編の際にも必ず残してください。』といったような注意文を入れてでも、最初からの考えである、『高度な知識がなくても簡単いろいろな機能が利用でき、簡単に拡張可能なListView』に沿うものに仕上がれば、前回の質問でのコードにコメントの出力を追加だけで十分だと思います。

    一緒にコメントの出力が可能なのか、可能ならどうすればイイのか教えて頂けたらと思います。

    • 編集済み miwa3125 2013年10月30日 22:24
    2013年10月30日 21:54
  •  「独自の機能を持つ ListView コントロールを作成したい」というところに応えると、これを参考にされるといいでしょう。→「C# List View v1.3
     このコントロールは、ListView クラスからではなく Control クラスから派生し、表示するアイテムも CollectionBase クラスから派生することで、あなたが悩んでいらっしゃる問題が発生しないようにされています。

    # 登録が2004年で、プロジェクトが Visual Studio 2003 なところは、苦労がありそうです。

    # 「article」から、「Chapters and Sections > Desktop Development > List Controls」で、類似のコントロールのリストが表示されます。


    Jitta@わんくま同盟

    2013年11月1日 11:38
  • プロジェクトのプロパティのビルドタブから XML ドキュメントをコンパイルするようにし、一緒に配布すれば IntelliSense やオブジェクトブラウザーでコメントを見ることはできます。
    ただ、常に見るかと言われると微妙なので、弱い制約と言えるかもしれません。

    ところで、継承は基底クラスと同じような使い方ができないような用途、今回のように機能のほとんどを流用して一部を改変する目的には向いていません。
    少なくとも、基底クラスのインターフェースの都合が悪くて隠蔽したいと思った時点で、継承を否定しているように感じられます。
    (参考:http://iwatam-server.sakura.ne.jp/software/devintro/inheritance/inheritance/

    このようなケースでは委譲を考えた方が最終的にすっきりするかもしれません。
    インターフェースの制約を受けず、きれいにまとめられるからです。(Jitta さんが紹介されている事例がそれにあたりそう)
    ただ、ListView は非常に高機能なので、それと同等の使い勝手を実現するのはデザイナーを支援するためのクラス、シリアライズのためのクラスなど、いろいろと書かないといけないものが多いので苦難の道ではあります…。

    委譲を選びたくない心情もわかりますが、それによって受ける制約・デメリットは残念ながら受容するしかないと思います。

    2013年11月1日 23:42
    モデレータ
  •  「独自の機能を持つ ListView コントロールを作成したい」というところに応えると、これを参考にされるといいでしょう。→「C# List View v1.3
     このコントロールは、ListView クラスからではなく Control クラスから派生し、表示するアイテムも CollectionBase クラスから派生することで、あなたが悩んでいらっしゃる問題が発生しないようにされています。

    # 登録が2004年で、プロジェクトが Visual Studio 2003 なところは、苦労がありそうです。

    # 「article」から、「Chapters and Sections > Desktop Development > List Controls」で、類似のコントロールのリストが表示されます。


    Jitta@わんくま同盟

    お返事が遅くなってしまい、申し訳ございません。

    やはり、追加するという考え方より、作るという方が実現するのですかねぇ。。。

    参考にとのサイトは、去年Columnsにプロパティを追加したいって思ったときに見つけてました。

    が、訳せないという理由で、途中で挫折しました。

    日本語での解説だったら、訳せないという理由で挫折はないのですけどねぇ。。。

    頼まれているアプリは急ぐ必要があるので、前回教えて頂いている方法で対応して、終わり次第、もう一度チャレンジしてみます。

    勉強になるのは事実ですからね。

    2013年11月4日 19:11
  • プロジェクトのプロパティのビルドタブから XML ドキュメントをコンパイルするようにし、一緒に配布すれば IntelliSense やオブジェクトブラウザーでコメントを見ることはできます。
    ただ、常に見るかと言われると微妙なので、弱い制約と言えるかもしれません。

    ところで、継承は基底クラスと同じような使い方ができないような用途、今回のように機能のほとんどを流用して一部を改変する目的には向いていません。
    少なくとも、基底クラスのインターフェースの都合が悪くて隠蔽したいと思った時点で、継承を否定しているように感じられます。
    (参考:http://iwatam-server.sakura.ne.jp/software/devintro/inheritance/inheritance/

    このようなケースでは委譲を考えた方が最終的にすっきりするかもしれません。
    インターフェースの制約を受けず、きれいにまとめられるからです。(Jitta さんが紹介されている事例がそれにあたりそう)
    ただ、ListView は非常に高機能なので、それと同等の使い勝手を実現するのはデザイナーを支援するためのクラス、シリアライズのためのクラスなど、いろいろと書かないといけないものが多いので苦難の道ではあります…。

    委譲を選びたくない心情もわかりますが、それによって受ける制約・デメリットは残念ながら受容するしかないと思います。

    お返事が遅くなってしまい、申し訳ございません。

    自作のDLLファイルをすでに作っていて、それに追加するという方法を繰り返してるので、XML ドキュメントの作成は行っています。

    自分で作ったとはいえ、何の説明もない状態では、何の処理をするために使うのか、引数は何を渡すのか、戻り値は何なのか、時間が経ったらすべて思い出せなくなる気がしたので。。。

    知識的にも一から作る自信がないし、分からないことに遭遇したときに質問をする場にも困ったので、英語で説明されているサイトは『訳せない』というもう一つの理由で目を通す程度で終わらせることが多くありました。

    拡張という方法は、ある意味『逃げ』なのは分かっています。

    そうするからには、基にあるものをすべて受け入れなければいけないとも思っています。

    ただ今回の場合、第三者が利用した際のコードだけでも判断ができるようにする目的で追加したことで、まったく同じメソッドが継承元との引数の型違いだけで存在してしまうので、ひとつにできるのであれば、基にあるものを隠すなどしたいと思ったので、この質問をさせてもらいました。

    2013年11月4日 19:35