基底クラスの基底クラスにアクセスしたい
C#では base というキーワードで継承元のクラスのメンバにアクセスできます。では継承元の元はどうするか、つまり base.base.Hoge(); のようなことがやりたいという場合のお話です。しかし残念ながらbaseは繋げて書けません。
newで再定義している場合
メンバを継承する際に、元の定義をnewで潰して再定義している場合は比較的簡単にできます。
class A { public void Hoge() { Console.WriteLine("A"); } } class B : A { public new void Hoge() { Console.WriteLine("B"); } } class C : B { public new void Hoge() { ((A)this).Hoge(); } } static class Program { static void Main(string[] args) { C c = new C(); c.Hoge(); // A } }
overrideで再定義している場合
これはかなり厳しいと思われます。キャストしても実体はCのままですから、overrideで再定義されたメソッドが呼ばれてしまい、StackOverflowExceptionが発生します。これはまず設計を見直すべきな気もします。
とはいえ、実用云々は置いといて、諦めるのも癪なのでなんとかやってみます。例えば、こちらのページにあるような形で強制的に型を変えてやればできなくもありません。
http://csharper.blog57.fc2.com/blog-entry-214.html
このConvertTypeを拝借させて頂いて、実際にやってみます。(コメントは除いてあります)
class A { public virtual void Hoge() { Console.WriteLine("A"); } } class B : A { public override void Hoge() { Console.WriteLine("B"); } } class C : B { public override void Hoge() { ConvertType(this, typeof(A)); this.Hoge(); // this.HogeだけどA.Hogeが呼ばれる! ConvertType(this, typeof(C)); } static unsafe void ConvertType(object target, Type newType) { IntPtr newTypeHandle = newType.TypeHandle.Value; GCHandle targetGCHandle = GCHandle.Alloc(target, GCHandleType.Normal); try { void* entryPointer = (void*)GCHandle.ToIntPtr(targetGCHandle); void* targetPointer = *((void**)entryPointer); IntPtr* typeHandlePointer = (IntPtr*)targetPointer; *typeHandlePointer = newTypeHandle; } finally { targetGCHandle.Free(); } } } static class Program { static void Main(string[] args) { C c = new C(); c.Hoge(); // A } }
なんとも恐ろしいコードですが、この場合ではうまくいきました。実際に使うのはよしたほうがよさそうです。
あとはリフレクションという手もありそうですが、どちらにしろそこまでするぐらいなら別の手を考えましょう。
同じような悩みについてのページ。
http://social.microsoft.com/Forums/ja-JP/csharplanguage/thread/7128c2fc-b1a3-4942-af8c-50033c0b5092http://social.msdn.microsoft.com/Forums/de-DE/csharpgeneralja/thread/fc8d2aa7-fb76-452a-9d83-f7d9a5adef81