7

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

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

例如:城市缓存数据库中的数据

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 可能还没有被使用(它可能没有在这个服务中使用)并且没有理由从数据库中加载它。

我的 reload all 方法看起来很像这样:

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。

4

5 回答 5

8

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

但是您不必在类中执行此操作,只需在其他位置(除了在任何这些静态类中)保留一个列表,该列表在每个静态类被初始化时填充。然后在您的重置功能中,只需遍历列表中的类。

于 2013-01-28T15:19:41.633 回答
2

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.

于 2013-01-28T15:24:28.013 回答
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。

于 2013-01-29T09:06:38.263 回答
1

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

实际上不需要做一个单例,只需要保留你的静态类,并在调用应该返回它的属性 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
         }
      }
   }
}
于 2013-01-28T15:20:10.660 回答
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
于 2013-01-28T15:37:20.947 回答