- PR -

C# 特定のプロパティへの外部からのアクセスを隠蔽したい

投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-05 10:14
★課題
Class1の"多数のメンバー"はClass2にそのまま継承したい。
ValueプロパティだけはClass2の外部からアクセスできないようにしたい。
Class1は既に設計済みで、Class1の構造は修正できない。
Class2を巧みに設計することで課題を解決する必要がある。
エレガントな実装方法があるなら、継承にこだわる必要は無い。
Class2をどう設計すれば良いか。

public class Class2 : Class1
{
// 下記のどちらの宣言を挿入してもValueプロパティへの外部からの
// アクセスを隠蔽できないように思える。
// private new Value{…}
// public override Value{…}
// どのように記述すれば良いのでしょうか?
}

public class Class1
{
public int Value
{
get
{
return temp;
}
set
{
temp = value;
}
}
private int temp;

// 多数のメンバー
… …

}

★この質問の背景としては下記のような具体例を想定している。


標準textBoxを修正して、newTextBoxを設計している。
textBoxには多数のメンバーがあるので、newTextBoxにそのまま継承したい。
TextプロパティはnewTextBox内で操作することに決めた。
newTextBox外部からTextを外部から直接操作されると危険である。
newTextBox外部からTextを見えないようにしたい。

ant
常連さん
会議室デビュー日: 2004/03/24
投稿数: 44
投稿日時: 2004-12-05 14:53
質問の直接的な解答ではありませんが、プロパティを変更されるのが
まずいのであれば、読み取り専用のプロパティでhide-by-nameして
やればどうでしょう?
cats
大ベテラン
会議室デビュー日: 2002/11/29
投稿数: 221
お住まい・勤務地: 東京
投稿日時: 2004-12-05 15:06
Class1で公開されているものを継承して非公開にはできないので、面倒でも継承せずにClass2を作成すればできるでしょう。

非公開でなくてもよいから呼べなくしたいのであれば、再定義して例外を投げるという手もあります。仮想でないと、継承元にキャストすれば呼べてしまいますが。
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-12-05 19:19
諸農です。

試してませんが、new修飾子で隠蔽できるかもしれませんね。


_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-05 23:47
1."private new"で隠蔽する方法

実はわたしも試みたのですが、単に"private new"を定義しても、
うまく隠蔽できないような気がします。皆さんはどうでしょうか。

2.Class2を一から作り直す方法

一から作り直すといってもひとつひとつ定義するのは面倒ですし、
保守面でも問題があります。
ところで、Reflectionを使えばClass1に定義されているプロパティの
コレクションを取得できます。
このコレクションからValueプロパティのみ削除したものを作成しておいて、
Class2に追加するというアイデアを持っています。
ですが、プロパティのコレクションをClass2に追加する方法が分かりません。
どうすれば良いでしょうか?
また、イベントやコンストラクタなどプロパティ以外のメンバーについても
同様に手を抜いてClass2に追加できればと思っています。
アドバイス宜しくお願いします。
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-12-06 03:31
こんばんは、meiです。

引用:

ひろしさんの書き込み (2004-12-05 23:47) より:
このコレクションからValueプロパティのみ削除したものを作成しておいて、
Class2に追加するというアイデアを持っています。
ですが、プロパティのコレクションをClass2に追加する方法が分かりません。
どうすれば良いでしょうか?


テキストボックスを含んだユーザコントロールを作成するのはどうでしょうか? ユーザコントロールならVisual Studioからメニュー1つで作成できますし、ビジュアル編集も可能です。(独自で作ったクラスでビジュアル編集に対応させるより楽)
iStation
大ベテラン
会議室デビュー日: 2003/12/08
投稿数: 158
投稿日時: 2004-12-06 08:58
引用:

meiさんの書き込み (2004-12-06 03:31) より:
こんばんは、meiです。

引用:

ひろしさんの書き込み (2004-12-05 23:47) より:
このコレクションからValueプロパティのみ削除したものを作成しておいて、
Class2に追加するというアイデアを持っています。
ですが、プロパティのコレクションをClass2に追加する方法が分かりません。
どうすれば良いでしょうか?


テキストボックスを含んだユーザコントロールを作成するのはどうでしょうか? ユーザコントロールならVisual Studioからメニュー1つで作成できますし、ビジュアル編集も可能です。(独自で作ったクラスでビジュアル編集に対応させるより楽)


この場合は、mei さんのおっしゃるとおり、
継承よりは Containment の方がよさそうですね。
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-06 14:21
meiさん、iStationさん、ご回答ありがとうございます。

わたしの理解度不足で解説の内容だけでは、どうすれば良いかわかりませんでした。
もう少し詳細にご説明いただければ助かります。
お手数をおかけしまうs。

わたしなりに説明のためのサンプルコードの作成してみました。。
例えば、サンプルコード中のtempの性質をどのようにPinkTextBoxに
結びつければ良いか分かりません。
TextBoxが持つ特徴を引き継ぎながらBackColorだけを隠蔽したい場合、
どうすれば良いのでしょうか。


<例題>
背景色がTextの文字列によって変わるPinkTextBoxを作成したい。
PinkTextBoxの機能
(1) 原則としては、TextBoxの性質を引き継いでいる。
(2) Textの値に連動して背景色が変わる
temp.Textが""の場合 → 背景色(BackColor)=ピンク
temp.Textが""で無い場合 → 背景色(BackColor)=白
(3) IsEmptyフラグの追加(Textの値が空であるか)
(4) BackColorへ直接参照も書き込みもできないよう完全に隠蔽する

※例題は、説明のために作られたものなので、確かに違和感を感じる部分があります。
 今回は、例題の設定にまつわる違和感には目をつぶってください。
 書き換えできないBackColorメソッドにoverrideすれば、結果的に最低限の安全は保証
 されます。今回は、余計な内部構造のみを部分的に隠蔽しつつ、
 できるだけエレガントにに実装する方法を学びたいと思っています。
 
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace WindowsApplication1
{
/// <summary>
/// UserControl1 の概要の説明です。
/// </summary>
public class PinkTextBox : System.Windows.Forms.UserControl
{
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public PinkTextBox()
{
// この呼び出しは、Windows.Forms フォーム デザイナで必要です。
InitializeComponent();

// TODO: InitializeComponent 呼び出しの後に初期化処理を追加します。
temp = new TextBox();
temp.TextAlignChanged += new EventHandler(temp_TextAlignChanged);

}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region コンポーネント デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion

// ***** 追加 *****
/// <summary>
/// 背景色がピンク色に変わるtextBoxのテンプレート
/// </summary>
private TextBox temp;

/// <summary>
/// Textの値が空の場合 → true
/// </summary>
protected bool IsEmpty
{
get
{
return temp.Text == "" ? true : false;
}
}
private bool isEmpty;

/// <summary>
/// Textプロパティが空であれば背景色をピンク色にする
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void temp_TextAlignChanged(object sender, System.EventArgs e)
{
System.Drawing.Color BackColor1 = System.Drawing.Color.Pink;
System.Drawing.Color BackColor2 = System.Drawing.Color.White;
temp.BackColor = (temp.Text == "") ? BackColor1 : BackColor2;
}


}
}

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