在我的自定义属性的静态构造函数中,我在已加载的程序集中搜索用我的属性修饰的所有类,并对它们执行一些操作。
我希望在运行时尽快调用静态构造函数,最好是在执行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");
答案 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工厂的访问,这样你就不需要使用它了。