控制何时调用静态构造函数

时间:2009-12-11 07:06:54

标签: c# attributes static-constructor

在我的自定义属性的静态构造函数中,我在已加载的程序集中搜索用我的属性修饰的所有类,并对它们执行一些操作。

我希望在运行时尽快调用静态构造函数,最好是在执行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);
        }
    }
}

更新

我最终使用静态方法的抽象属性。通过这种方式,我可以获得尽可能多的属性,并通过调用这一方法将它们全部应用于指定的配置。

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 个答案:

答案 0 :(得分: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,这是永远一件好事......

答案 1 :(得分:3)

正如Marc所说,如果我是你,我会在Main明确地做到这一点。

可以使用Type.TypeInitializer属性显式调用类型的类型初始值设定项并调用它。但是,这将导致它再次运行,即使它已经运行,这可能会产生意想不到的结果。

我个人会完全将该代码移出静态初始化程序。它的配置代码 - 为什么不将它作为一个可以显式调用的静态方法?我甚至不确定我是否会在属性类本身中拥有它,但至少明确地调用:

CascadeOnUpdateAttribute.ConfigureDb4oFactories();

比调用虚方法或以其他方式强制类型初始化更清晰,只是为了产生副作用。

答案 2 :(得分:2)

您可以通过调用

来避免静态虚拟方法
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(CascadeOnUpdateAttribute).TypeHandle)

答案 3 :(得分:1)

我认为使用静态构造函数闻起来;我会考虑重构你的代码来控制对db4o工厂的访问,这样你就不需要使用它了。