#プログラマが思春期の娘に言われると傷つく一言 – Togetterまとめ
http://togetter.com/li/294232
を見ていて、「お父さんと同じ名前空間に居たくない!」と「パパのコードと一緒にビルドしないで!」が秀逸だったので C# で実現してみました。正確には名前空間じゃなくて Prada というクラス名を見せないようにします(まあ、クラス名をネストの深い名前空間に入れておけば、名前空間自体を探ることも難しいと思うのですが…これはあとで調べてみよう)。
単純に AliceRoom のアセンブリのクラスを他のアセンブリに公開したくない場合は、private なり internal を使えばよいのですが、そうなると Lolita に Prada を渡したく。Lewis(今回はお父さん役)には見せたくないけども、友達の Lolita とは共有したい場合は、InternalsVisibleTo 属性を使ってフレンド共有をします。こうすることで internal クラスが LolitaRoom から見えるという状態になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // Lolita クラスにのみ公開する [assembly: InternalsVisibleTo( "LolitaRoom" )] namespace AliceRoom { public class Alice : Room.IPerson { public void Init() { var bag = new Prada(); bag.Owner = "Alice" ; bag.Content = "my secret" ; this .box = bag; } public string GetBagContent() { var bag = box as AliceRoom.Prada; if (bag == null ) return "NONE" ; else return bag.Content; } } /// <summary> /// Plada クラスは LolitaRoom にのみ公開 /// </summary> internal class Prada { // Owner を設定できるのは Alice だけ public string Owner { get ; internal protected set ; } // コンテンツは Lolita も取得できる public string Content { get ; set ; } } } |
さて、もうひと息やって、Prada オブジェクトを Lolita に渡すことにします。
渡し方をどうするかというと、Alice.Post( Lolita ) みたいに渡したいですよね。実際に渡す Prada オブジェクトは、以下の Main から見えない(公開しているのは LolitaRoom アセンブリのみ)ので、何を誰に渡すのかが必要です。しかし「何を」渡すか自体は、Alice と Lolita しか知らないので、どうやって渡すかは試案のしどころ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Program { static void Main( string [] args) { var alice = new AliceRoom.Alice(); var lolita = new LolitaRoom.Lolita(); var lewis = new LewisRoom.Lewis(); // Pradaを作成 alice.Init(); // AliceRoom.Prada は見れない Console.WriteLine( "alice room : {0}" , alice.GetBagContent()); Console.WriteLine( "lolita room: {0}" , lolita.GetBagContent()); // Lolitaに渡す alice.Post(lolita); Console.WriteLine( "alice room : {0}" , alice.GetBagContent()); Console.WriteLine( "lolita room: {0}" , lolita.GetBagContent()); // Lwewis から AliceRoom.Prada は見れない } } |
仕方がないので、渡すためのインターフェースを作ります。ここでは、IPerson インターフェースを作って object 型で渡しているのですが、途中シリアライズ化する方法もあります。そういう意味では INotify を使ってもいいと思います。
1 2 3 4 5 6 7 8 9 10 11 | namespace Room { public abstract class IPerson { protected object box { get ; set ; } public void Post(IPerson dest) { dest.box = this .box; this .box = null ; } } } |
あと、Prada の Owner 情報は Alice なので、Lolita が勝手に書き換えてはいけません。クラス情報は Lolita に公開するけど、Prada.Owner.set は Alice だけが使えるように「internal protected set」にしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | namespace LolitaRoom { public class Lolita : Room.IPerson { public void Post(Room.IPerson dest, object obj) { this .box = obj; } public string GetBagContent() { var bag = box as AliceRoom.Prada; if (bag == null ) return "none" ; else return bag.Content; } } } |
そんな訳で「お父さんと同じ名前空間に居たくない!」を実現したのがこちら。
サンプルコードは github
https://github.com/moonmile/DontLookMyNamespace