4

カスタム属性の静的コンストラクターで、ロードされたアセンブリから属性で装飾されたすべてのクラスを検索し、それらに対して何らかのアクションを実行します。

静的コンストラクターは、実行時にできるだけ早く、できればstatic void Main()エントリ ポイントの実行前に呼び出されるようにしたいと考えています。

現在、属性を呼び出した後にのみ呼び出されます。プログラムの他の場所でそのような呼び出しを行うこともできますが、理想的には、属性の機能は自己完結型です。

答えを探して、MSDNでこれを読みました:

ユーザーは、静的コンストラクターがプログラムで実行されるタイミングを制御できません。

しかし、確実に、静的コンストラクターを ASAP と呼ぶには、トリッキーで、狡猾で、いたずらな回避策があります。おそらく、属性、反射、またはその他の種類の魔法を使用できます。それはできますか?

人々は間違いなく、私が要求したことを行う正当な理由はないと言うので、目的とコードを示します。属性を使用して、db4oファクトリを宣言的に構成しようとしています。接続を確立した後で属性の静的コンストラクターが呼び出された場合、それは効果がなく、役に立ちません。したがって、私のプログラムがそのような接続を確立する機会を得る前に、それを呼び出す必要があります。

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
sealed public class CascadeOnUpdateAttribute : Attribute
{
    public bool Flag { get; private set; }

    public CascadeOnUpdateAttribute() : this(true) { }

    public CascadeOnUpdateAttribute(bool flag)
    {
        Flag = flag;
    }

    static CascadeOnUpdateAttribute()
    {
        var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
          from type in assembly.GetTypes()
          from attribute in type.GetCustomAttributes(typeof(CascadeOnUpdateAttribute), false).Cast<CascadeOnUpdateAttribute>()
          select new { Type = type, Cascade = attribute.Flag };

        foreach (var target in targets)
        {
            Db4oFactory.Configure().ObjectClass(target.Type).CascadeOnUpdate(target.Cascade);
        }
    }
}

アップデート:

静的メソッドで抽象属性を使用することになりました。このようにして、好きなだけ属性を派生させることができ、この 1 つのメソッドを呼び出すことで、指定された構成にすべての属性が適用されます。

public abstract class Db4oAttribute : Attribute
{
    public abstract void Configure(IConfiguration config, Type type);

    public static void ApplyAttributes(IConfiguration config)
    {
        var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
          from type in assembly.GetTypes()
          from attribute in type.GetCustomAttributes(typeof(Db4oAttribute), false).Cast<Db4oAttribute>()
          select new { Type = type, Attribute = attribute };

        foreach (var target in targets)
        {
            target.Attribute.Configure(config, target.Type);
        }
    }
}

そして呼び出しサイト:

Db4oAttribute.ApplyAttributes(Db4oFactory.Configure());
_db = Db4oFactory.OpenFile("Test.db4o");
4

4 に答える 4

3

マークが言うように、もし私があなただったら、はっきりとそうしMainます。

プロパティを使用して明示的に型の型初期化子を呼び出し、それを呼び出すことができます。Type.TypeInitializerただし、これにより、既に実行されている場合でも再度実行され、予期しない結果が生じる可能性があります。

個人的には、そのコードを静的初期化子から完全に移動します。これは構成コードです。明示的に呼び出すことができる静的メソッドにしないのはなぜですか? 属性クラス自体にそれがあるかどうかさえわかりませんが、少なくとも明示的に呼び出します:

CascadeOnUpdateAttribute.ConfigureDb4oFactories();

副作用を得るために、ダミーメソッドを呼び出したり、他の方法で型の初期化を強制したりするよりも明確です。

于 2009-12-11T07:15:40.663 に答える
3

静的コンストラクターを呼び出したい場合は、型にダミー メソッドを追加し、コードの先頭で呼び出すだけです (Mainなど)。それが些細な/空のメソッドである場合は、インライン化しないなどのマークを付けることができます.

class SomeType {
    static SomeType() {
        Console.WriteLine("SomeType.cctor");
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void Init() { }
}

static class Program {
    static void Main() {
        SomeType.Init();
        Console.WriteLine("hi");
    }
}

リフレクションを使用して静的コンストラクターを呼び出すことができますが、お勧めしません。リフレクションを使用すると、実際に .cctor を複数回呼び出すことができますが、それは決して良いことではありません...

于 2009-12-11T07:11:00.050 に答える
2

呼び出すことにより、静的ダミーメソッドを回避できます

System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(CascadeOnUpdateAttribute).TypeHandle)
于 2010-11-11T17:32:45.550 に答える
1

静的コンストラクターの使用は臭いと思います。コードをリファクタリングして db4o ファクトリへのアクセスを制御し、使用する必要がないようにすることを検討します。

于 2009-12-11T07:16:34.050 に答える