C#/friendクラスの代替案 のバックアップ差分(No.2)
更新- 追加された行はこの色です。
- 削除された行はこの色です。
[[公開メモ]] #contents * friend クラスとは [#t75f84fc] 密接に関連する2つのクラス、ClassA と ClassB とがあったとき、 他のクラスには公開しないが、お互いの間でのみ公開したいメソッドを 実装したくなる事が多々あります。 C++だとこのようなときに、お互いを friend クラスとして宣言することで、 外から見ると private なメソッドに自由にアクセスすることができるようになります。 C++だとこのようなとき、お互いを friend クラスとして宣言することで、 外から見ると private なメソッドに、お互いの間でだけ自由にアクセスできる ようになります。 * C# では [#med36db1] * C# の問題 [#med36db1] C# では friend はありません。 ところが C# には friend はありません。 代わりに internal というのがあるのですが、friend に比べて公開される範囲が広すぎて 完全に代替とすることができないところです。 似たような機能として internal というのがあるのですが、friend に比べて公開される範囲が 広すぎるので、完全に代替とすることができず、結構あちこちで議論の的になっています。 こういう場合、インターフェースを使うと、friend に似た効果を得られる事に気づきました。 -[[フレンドクラスに対する代替案>http://www.google.co.jp/url?sa=U&start=1&q=http://bbs.wankuma.com/index.cgi%3Fmode%3Dal2%26namber%3D7138%26KLOG%3D7&ei=UJ-PScykFoiU6gPu0um1Cg&usg=AFQjCNEPQcXCNVnqZhsEq526MW3doVSF2Q]] -[[C#への期待。アンダースからの返答 − @IT>http://www.google.co.jp/url?sa=U&start=4&q=http://www.atmarkit.co.jp/fdotnet/insiderseye/20060215cscommunity/cscommunity_02.html&ei=UJ-PScykFoiU6gPu0um1Cg&usg=AFQjCNHK3iwgAkMt0olEa3_MwaYBjo24fw]] -[[C# には friend キーワードがない>http://frog.raindrop.jp/knowledge/archives/002237.html]] -[[Google で "c#" friend を検索>http://www.google.co.jp/search?q=%22c%23%22+friend&lr=lang_ja&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official]] 当たり前の事なのかもしれませんが、不思議と他で同様の記事を発見できなかったので、 一応ここにメモしておきます。 おそらく一番の問題は、アセンブリを分けていない状況でコーディングしていると、 実際には必要とされない internal なメンバーがインテリセンスに現れてしまい、 誤って呼び出してしまったり、本当に呼び出したいメンバーを探すのが大変に なってしまったりすることだと思います。 public class ClassA: B.IClassA { void B.IClassA.privateMemberForClassB() { // このメンバーは private } } * インターフェースを用いた解決策 [#t2ec0098] public class B { internal interface IClassA { void privateMemberForClassB(); } こういう場合、インターフェースを使うと、friend よりも限定した形で、 特定のメソッドのみを、特定のクラスにのみ公開する事ができる事に気づきました。 public AccessToPrivate(ClassA a) { // キャストしたときだけ操作できる ( (IClassA)a ).privateMemberForClassB(); } } 当たり前の方法なのかもしれませんが、不思議と他で同様の記事を発見できなかったので、 一応ここにメモしておきます。 LANG:C# // ClassB からのみアクセス可能な private なメンバー // privateMemberForClassB を持つクラス public class ClassA: ClassB.IClassA { void ClassB.IClassA.privateMemberForClassB() { // このメンバーは private } } // ClassA の private メンバー // privateMemberForClassB にアクセスするクラス public class ClassB { // 同じアセンブリ内、あるいは ClassB および // その子孫クラスからのみ使えるインターフェース protected internal interface IClassA { void privateMemberForClassB(); } // 実際にアクセスするコードの例 public void AccessToPrivate(ClassA a) { // キャストしたときだけ操作できる ( (IClassA)a ).privateMemberForClassB(); } } もちろん、同じアセンブリ内で、わざわざ a を B.IClassA にキャストするコードを 書けば該当コードにアクセスできてしまいますが、間違って呼び出してしまうとか、 インテリセンスを汚してしまうとか、そういった問題はこの方法で回避できると思います。 インテリセンスを汚してしまうとか、そういった、本来解決したかった問題は この方法で回避できていると思います。 ClassA のプライベート関数を virtual にすることはできませんが、もともと インターフェース経由でのアクセスになりますので、子孫クラスで定義し直せば virtual と同様の効果が得られます。 非常に頻繁に呼び出される関数を、 このようにインターフェース経由の呼び出しにしてしまうと、 パフォーマンス的な問題が発生する可能性もありますが、 それ以外に関しては、コーディングの手間としても、 コードの読みやすさとしても、 ほとんど不都合の感じられない記述になっていると思います。 (2009/02/09) * コメント [#p09af981] #article_kcaptcha
Counter: 46400 (from 2010/06/03),
today: 1,
yesterday: 5