#プログラマが思春期の娘に言われると傷つく一言 – Togetterまとめ
http://togetter.com/li/294232
を見ていて、「お父さんと同じ名前空間に居たくない!」と「パパのコードと一緒にビルドしないで!」が秀逸だったので C# で実現してみました。正確には名前空間じゃなくて Prada というクラス名を見せないようにします(まあ、クラス名をネストの深い名前空間に入れておけば、名前空間自体を探ることも難しいと思うのですが…これはあとで調べてみよう)。
単純に AliceRoom のアセンブリのクラスを他のアセンブリに公開したくない場合は、private なり internal を使えばよいのですが、そうなると Lolita に Prada を渡したく。Lewis(今回はお父さん役)には見せたくないけども、友達の Lolita とは共有したい場合は、InternalsVisibleTo 属性を使ってフレンド共有をします。こうすることで internal クラスが LolitaRoom から見えるという状態になります。
// 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 しか知らないので、どうやって渡すかは試案のしどころ。
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 を使ってもいいと思います。
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」にしておきます。
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