これはあなたの目的に役立つかもしれませんが、私は確かにいくつかの例外処理を含め、それがなぜそしてどのように機能するかについての大量のドキュメントをその実装に伴います。
の静的コンストラクターBase
が(1回)実行されると、現在アプリドメインにロードされているすべてのアセンブリがカタログ化され、から派生するタイプが選択されBase
ます。それらを繰り返して、静的コンストラクターを実行します。ただし、これにより、各実装のcctorが1回だけ実行されることが保証されなくなったことに注意してください。そのアサーションを再作成するには、各実装にロジックを追加する必要があります。さらに、cctor forBase
が実行された後にロードされる型は、のメソッドの呼び出しによって初期化されません。Base
仮想メソッドをシミュレートするには、new
キーワードを使用して基本メソッドを非表示にします。宣言しているクラスの名前で修飾することにより、基本メソッドを呼び出すことができます(B
例のクラスのように)
using System;
using System.Linq;
using System.Runtime.CompilerServices;
namespace ConsoleApplication6
{
public class Base
{
static Base()
{
Console.WriteLine("Base cctor");
var thisType = typeof (Base);
var loadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes());
var derivations = loadedTypes.Where(thisType.IsAssignableFrom);
foreach(var derivation in derivations)
{
RuntimeHelpers.RunClassConstructor(derivation.TypeHandle);
}
}
public static void Foo()
{
Console.WriteLine("Bar");
}
}
public class A : Base
{
static A()
{
Console.WriteLine("A cctor");
}
}
public class B : Base
{
static B()
{
Console.WriteLine("B cctor");
}
public new static void Foo()
{
Console.WriteLine("Bar!!");
Base.Foo();
}
}
class Program
{
static void Main()
{
Console.WriteLine("A:");
A.Foo();
Console.WriteLine();
Console.WriteLine("B:");
B.Foo();
Console.WriteLine();
Console.WriteLine("Base:");
Base.Foo();
Console.ReadLine();
}
}
}
編集
別のオプションは、CRTP(またはC#パラダイムのCRGP)または不思議なことに繰り返されるテンプレート(ジェネリック)パラメーターパターンにあります
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApplication6
{
public class Base<T>
where T : Base<T>
{
static Base()
{
RuntimeHelpers.RunClassConstructor(typeof (T).TypeHandle);
}
public static void Foo()
{
Console.WriteLine("Bar");
}
}
public class Base : Base<Base>
{
}
public class A : Base<A>
{
static A()
{
Console.WriteLine("A cctor");
}
}
public class B : Base<B>
{
static B()
{
Console.WriteLine("B cctor");
}
public new static void Foo()
{
Console.WriteLine("Bar!!");
Base<B>.Foo();
}
}
class Program
{
static void Main()
{
Console.WriteLine("A:");
A.Foo();
Console.WriteLine();
Console.WriteLine("B:");
B.Foo();
Console.WriteLine();
Console.WriteLine("Base:");
Base.Foo();
Console.ReadLine();
}
}
}
この場合、静的メソッドを呼び出すと、A
実際にはメソッドが呼び出された方法Base<A>
とは異なるBase<B>
か、メソッドが呼び出された方法を判別して適切なcctorを実行できBase
ます。