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

时间:2013-01-28 15:13:07

标签: c# static-constructor

我有一些类来缓存数据库中的数据,这些类在调用静态构造函数时会加载数据。

我需要在所有这些类中调用静态Reload方法,除了那些尚未初始化的类。

例如: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;
    }
}

问题是City可能尚未使用(可能未在此服务中使用),因此没有理由从数据库加载它。

我重新加载所有方法看起来很像这样:

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;   
    }
}

我需要一点帮助来实现StaticConstructorHasBeenCalled。

5 个答案:

答案 0 :(得分:7)

乍一看,我认为这可能是<grin>量子力学哥本哈根解释可能适用的问题(“一看到它就会改变 EM>“)。 </grin> I.e.你在课堂上做的任何事情,以观察它是否已被初始化可能会 导致 它初始化自己......

但是你不必在类中执行它,只需在其他地方(除了这些静态类之外)保留一个列表,该列表在初始化时由每个静态类填充。然后在你的重置函数中,只需遍历列表中的类。

答案 1 :(得分:2)

如果你有几个这样的类,那么如何通过工厂或经理类来控制它们的实例化。 这可以跟踪已使用的内容,并在适当的时候调用重新加载方法。

答案 2 :(得分:1)

您不应该在静态构造函数中使用长时间运行的操作,或者至少它们不应该同步运行。静态构造函数隐式运行,当隐式执行需要很长时间时,它会产生有趣的错误:)

另外,如果你使用静态构造函数,方法和诸如维护状态的东西,尝试在完全静态的类中隔离它们,因此在大多数情况下它们将像单例一样运行。我会将实现更改为以下内容:

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

答案 3 :(得分:1)

我问是否有办法查看是否调用了静态构造函数。我认为答案是否定的,但解决方法是创建一个可以跟踪存储库的管理器。 目标是尽可能少地改变现有的类。

我对经理类的解决方案是:

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();
    }
}

使用City类的示例,更改将仅限于静态构造函数。

public class City
{
    // ...

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

    // ...
}

我的ReloadAll方法就像下面这样简单:

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

感谢您的所有答案,我已经奖励了每个人,他们建议某种经理作为解决问题的方法。

这个解决方案的缺点是,每当有人创建需要重新加载/更新/清除一次的存储库时,他们必须记住使用RepositoryManager。

答案 4 :(得分:0)

您可以使用单例模式,并添加一个字段,告诉您是否已创建唯一实例

实际上不需要创建单例,只需保留静态类,并在调用应该返回它的属性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
         }
      }
   }
}