简体   繁体   English

如何检查是否已调用静态构造函数?

[英]How to check if a static constructor has been called?

I have some classes that caches data from a database, these classes are loaded with data when their static constructor gets called. 我有一些类来缓存数据库中的数据,这些类在调用静态构造函数时会加载数据。

I need to call a static Reload method at all these classes, except those that is not initialized yet. 我需要在所有这些类中调用静态Reload方法,除了那些尚未初始化的类。

Eg: City caches data from a database 例如:City缓存数据库中的数据

public class City
{
    public City Get(string key)
    {
        City city;
        FCities.TryGetValue(key, out city);
        return city;
    }
    private static Dictionary<string, City> FCities;

    static City()
    {
        LoadAllCitiesFromDatabase();
    }

    public static void Reload()
    {
        LoadAllCitiesFromDatabase();
    }

    private static void LoadAllCitiesFromDatabase()
    {
        // Reading all citynames from database (a very slow operation)
        Dictionary<string, City> loadedCities = new Dictionary<string, City>();
        ...
        FCities = loadedCities;
    }
}

The problem is that City might not have been used yet (it might not be used in this service) and there is no reason to load it from the database then. 问题是City可能尚未使用(它可能不会在此服务中使用),因此没有理由从数据库加载它。

My reload all method looks much like this: 我重新加载所有方法看起来很像这样:

public static class ReloadAll
{
    public static void Do()
    {
        foreach (Type classType in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.IsClass && !t.IsAbstract))
        {
            MethodInfo staticReload = classType.GetMethods().FirstOrDefault(m => m.IsStatic && m.IsPublic && m.ReturnType == typeof(void) && m.Name == "Reload" && m.GetParameters().Length == 0);
            if (staticReload != null)
            {
                if (StaticConstructorHasBeenCalled(classType))
                    staticReload.Invoke(null, null);
            }
        }
    }

    private bool StaticConstructorHasBeenCalled(Type classType)
    {
        // How do I check if static constructor has been called?
        return true;   
    }
}

I need a little help with implementing StaticConstructorHasBeenCalled. 我需要一点帮助来实现StaticConstructorHasBeenCalled。

At first glance, I thought this could be an issue where <grin> Quantum Mechanical Copenhagen interpretation might apply (" As soon as you look at it, it changes "). 乍一看,我认为这可能是一个问题,其中<grin>量子力学哥本哈根解释可能适用(“一看到它,它就会改变 ”)。 </grin> Ie anything you do in the class to observe whether it has been initialized would probably cause it to initialize itself... </grin>即你在课堂上做的任何事情,以观察它是否已被初始化可能会导致它自己初始化......

But you don't have to do it in the class, just keep a list somewhere else (other than in any of these static classes) that is populated by every static class when it gets initialized. 但是您不必在类中执行此操作,只需在其他位置(除了这些静态类之外)保留一个列表,该列表在初始化时由每个静态类填充。 Then in your reset function, just iterate through the classes in the list. 然后在你的重置函数中,只需遍历列表中的类。

If you have several of these classes, how about controlling their instantiation through a factory or manager class. 如果您有几个这样的类,那么如何通过工厂或经理类来控制它们的实例化。 This could keep track of which have been used and call the reload methods where appropriate. 这可以跟踪已使用的内容并在适当时调用重新加载方法。

You should not use long-running operations in the static constructor, or at least, they should not run synchronously. 您不应该在静态构造函数中使用长时间运行的操作,或者至少它们不应该同步运行。 Static constructor run implicitly, and when implicit execution takes significant time, it makes for interesting bugs :) 静态构造函数隐式运行,当隐式执行占用大量时间时,它会产生有趣的错误:)

Also, if you do use static constructors, methods and whatnot that maintain state, try to isolate them in a fully static class, so they will, for most scenarios, act like singletons. 此外,如果您确实使用静态构造函数,方法以及维护状态的东西,请尝试在完全静态的类中隔离它们,因此在大多数情况下,它们将像单例一样运行。 I would change the implementation to something along these lines: 我会将实现更改为以下内容:

public static class CityRepository
{
   private static bool areCitiesLoaded;
   private List<City> cities;

   static CityRepository()
   {
     areCitiesLoaded = false;
     cities = new List<City>();
   }

   //method that will be called in all other method, to ensure
   //that the cities are loaded
   private static void EnsureLoad()
   {
      if (!areCitiesLoaded)
      {
        LoadAllCitiesFromDatabase();
        areCitiesLoaded = true;
      }
   }
}

public class City {} //city instance methods

I asked if there was any way to see if a static constructor was called. 我问是否有任何方法可以查看是否调用了静态构造函数。 I think that the answer was no, but a workaround would be to create a manager that could keep track of repositories. 我认为答案是否定的,但解决方法是创建一个可以跟踪存储库的管理器。 The goal was to change as little as possible to the existing classes. 目标是尽可能少地改变现有的类。

My solution to a manager class is: 我对经理类的解决方案是:

public static class RepositoryManager
{
    public delegate void Reload();
    private static List<Reload> FRepositories = new List<Reload>();

    public static void Register(Reload repository)
    {
        lock (FRepositories)
        {
            FRepositories.Add(repository);
        }

        repository();
    }

    public static void ReloadAll()
    {
        List<Reload> list;
        lock (FRepositories)
        {
            list = new List<Reload>(FRepositories);
        }

        foreach (Reload repository in list)
            repository();
    }
}

Using the example with the City class the changes would be limited to the static constructor. 使用City类的示例,更改将仅限于静态构造函数。

public class City
{
    // ...

    static City()
    {
        RepositoryManager.Register(LoadAllCitiesFromDatabase);
    }

    // ...
}

My ReloadAll method would then be as simple as: 我的ReloadAll方法就像下面这样简单:

public void ReloadAll()
{
    RepositoryManager.ReloadAll();
}

Thank you for all your answers, I have rewarded each of you that suggested some kind of a manager as a solution to the problem. 谢谢你的所有答案,我已经奖励你们每个人建议某种经理作为问题的解决方案。

The drawback of this solution is that whenever someone creates a repository that needs to be reloaded/updated/cleared once in a while they have to remember to use the RepositoryManager. 此解决方案的缺点是,每当有人创建需要重新加载/更新/清除一次的存储库时,他们必须记住使用RepositoryManager。

you could use the singleton pattern, and add a field that will tell you if the unique instance has already been created 您可以使用单例模式,并添加一个字段,告诉您是否已创建唯一实例

actually no need to make a singleton, just keep your static class, and load the data when the property getter that should return it is called: 实际上不需要创建单例,只需保留静态类,并在调用应该返回它的属性getter时加载数据:

static class City
{
   static bool _loaded = false;

   public bool Loaded { get { return _loaded; } }

   public static List<C> Data
   {
      get
      {
         if (!_loaded)
         {
             doLoading();
             _loaded = true
         }
      }
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM