- PR -

継承元のパブリックメソッドを外部に隠ぺいしたい

投稿者投稿内容
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2007-06-20 17:50
引用:

まどかさんの書き込み (2007-06-20 17:14) より:

C#はVBのShadowsとピッタンコのってないのかな?


new がそれです。

GDNJ でも過去に同様の質問があったような気がしますが、Shadows だけでは解決できません。継承クラス側に Private メンバとして Shadows (new) したとしても、基底クラスの同メンバが上書きされるわけではないので、基底クラスの Public なメンバには外部からアクセスできます。

エディタに表示しないだけならば、System.ComponentModel.EditorBrowsable 属性なのでしょうけど、結局のところ使用不可になるわけではないですね。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
さんぽ
会議室デビュー日: 2007/06/20
投稿数: 3
投稿日時: 2007-06-20 18:03
アップキャストしなければ呼び出せないようになら。

Interface IA
Sub AA()
End Interface

Public Class A
Implements IA

Private Sub AA() Implements IA.AA
Debug.WriteLine("A-AA")
End Sub
End Class

Public Class B
Inherits A
End Class

Dim b As New B
b.AA() 'ビルドできない
CType(b, IA).AA() 'AのAAが呼ばれる
Dim a As New A
a.AA() 'こっちもビルドできない
CType(a, IA).AA() 'AのAAが呼ばれる



[ メッセージ編集済み 編集者: 未記入 編集日時 2007-06-20 18:05 ]
jornada690
常連さん
会議室デビュー日: 2006/06/13
投稿数: 25
投稿日時: 2007-06-20 18:25
申し訳ございません。表現の仕方が悪かったです。
「コンパイルエラーとしたい==インテリセンスに出さないようにする」
と自分では判断していました。
EditorBrowsableAttribute属性でインテリセンスに表示しないこともできるのですね。
勉強になります。
ただし、派生クラスのインスタンスからのみ非表示にするということはできますでしょうか(都合が良すぎますでしょうか)。

実際には、コンパイルエラーとしたいのですが、
一郎さんの例をお借りすると、

コード:
--------------------------------------------------------------------------------

class Base
{
public virtual void F() { Console.WriteLine("Base.F"); }
public virtual void G() { Console.WriteLine("Base.G"); }
}

class Derived : Base
{
public override void F() { Console.WriteLine("Derived.F"); }

}

(コードの中)
Derived d = new Derived();
Base b = d;

b.F(); //出力 Derived.F
b.G(); //出力 Base.G
d.F(); //出力 Derived.F
d.G(); //出力 Base.G(●希望としてはコンパイルエラーとしたい)
--------------------------------------------------------------------------------

●印の箇所でコンパイルエラーにするような技(?)があればと思ったのですが。
このようなことがはたして可能なのかの見分けができればと思いまして。

いま思いついたのですが
class Derived : Base
{
public override void F() { Console.WriteLine("Derived.F"); }
public override void G() { #error コンパイルエラー! }
}
というようにすればよいのですかね。

jornada690
常連さん
会議室デビュー日: 2006/06/13
投稿数: 25
投稿日時: 2007-06-20 18:33
すいません
#errorディレクティブの使い方間違えてました。
さんぽ
会議室デビュー日: 2007/06/20
投稿数: 3
投稿日時: 2007-06-20 18:39
ObsoleteAttribute使ったらできました。

Public Class A
Public Sub AA()
Debug.WriteLine("A-AA")
End Sub
End Class

Public Class B
Inherits A

<Obsolete("使用不可", True)> _
Public Shadows Sub AA()
Debug.WriteLine("B-AA")
End Sub
End Class

Dim b As New B
b.AA() 'ビルドできない

Dim a As New A
a.AA()
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2007-06-20 18:41
# 先に書かれちゃったけど、投稿しちゃえ。

継承クラス型からの呼び出しのみを防げれば良いのであれば、System.Obsolete 属性を使って使用禁止になるようにコンパイラに呼びかけてみるなんて方法がありますね。

コード:

    public class Class1 {
        public void MosaMosaAA() {
            MessageBox.Show("Class1.MosaMosaAA()");
            return;
        }
    }

    public class Class2 : Class1 {
        [System.Obsolete("基底クラスのメンバを使用してください。", true)]
        public new void MosaMosaAA() {
            MessageBox.Show("Class2.MosaMosaAA()");
            return;
        }
    }



たとえば、

コード:

    private static void TestMethod() {
        Class2 c2 = new Class2();
        c2.MosaMosaAA(); //これはコンパイル エラー
    }


これはコンパイル エラーとして防ぐことができます。

コード:

    private static void TestMethod() {
        Class1 c1 = new Class2();
        c1.MosaMosaAA(); //これは OK
    }


このように基底クラス型からの呼び出しについては防ぐことはできません。ご注意ください。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2007-06-20 18:43
引用:

jornada690さんの書き込み (2007-06-20 16:27) より:
クラス(A)にパブリックなメソッドAAがあり、クラス(A)のインスタンスからはメソッド(AA)を呼び出せるようにしたいが、
クラス(A)を継承するクラス(B)のインスタンスからはメソッド(AA)を隠ぺいする(参照できなくする)方法はあるのでしょうか?


無理。

委譲(オブジェクトコンポジション)じゃダメなの?

コード:

class A {
public void AA() {
// hoge-hohe
}

public void BB() {
// uja-uja
}
}

class B {
private A mA = new A();

public void BB() {
mA.BB();
}
}


ってな感じ。

[追記]
# 話が進んでいるのにも気づかず、とんちんかんな回答しちゃったよ。
# さっくり、無視しちゃってください。


[ メッセージ編集済み 編集者: かずくん 編集日時 2007-06-20 18:49 ]
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2007-06-20 18:49
リファクタリングというのをご存知でしょうか。
リファクタリングのきっかけとする不吉な匂いの中に「相続拒否」というのがあります。
つまり親クラスの機能などを引き継ぎたくないということです。

例えば、Carクラスにクラッチを操作する機能がpublicで定義されていたとします。
オートマチックトランスミッションの車(ATCar)クラスをCarクラスを継承して作った場合に、クラッチを操作する機能が外部に公開されているのは問題です。
そこで、ATCarクラスではクラッチ操作の機能を隠したいと思うわけですが、この場合まずクラス構成自体に疑問を持たなければいけません。
クラスの継承というのは、子クラスが親クラスそのものであるときに使用します。
よくある間違いは「親クラスの機能を使いたいから継承」というパターンです。

上の例で、Carクラスにクラッチ操作の機能がpublicで定義されているということが間違っていないとすると、車というのは外部からクラッチ操作ができるものということになります。
すると、ATの車は車ではありませんので、ATCarがCarを継承するのは間違いです。
クラッチ操作の機能が公開されていないものでも車でありうるなら、Carクラスにクラッチ操作の機能が定義されている事自体が間違いですのでそれを改めなければいけません。
クラッチ操作の機能が付いているのは車の中でもMTの車ということですので、Carから継承したATCarとMTCarというクラスを作り、それぞれのクラスにはそれぞれのクラスの機能を定義することになります。

そもそも、クラス(B)はクラス(A)の機能を使っているというだけなら、継承はせずにクラス(B)がクラス(A)に処理をお願いするような形になります。委譲って言いますけど。

[ メッセージ編集済み 編集者: 一郎 編集日時 2007-06-20 18:54 ]

スキルアップ/キャリアアップ(JOB@IT)