簡體   English   中英

如何檢查是否已調用靜態構造函數?

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

我有一些類來緩存數據庫中的數據,這些類在調用靜態構造函數時會加載數據。

我需要在所有這些類中調用靜態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。

乍一看,我認為這可能是一個問題,其中<grin>量子力學哥本哈根解釋可能適用(“一看到它,它就會改變 ”)。 </grin>即你在課堂上做的任何事情,以觀察它是否已被初始化可能會導致它自己初始化......

但是您不必在類中執行此操作,只需在其他位置(除了這些靜態類之外)保留一個列表,該列表在初始化時由每個靜態類填充。 然后在你的重置函數中,只需遍歷列表中的類。

如果您有幾個這樣的類,那么如何通過工廠或經理類來控制它們的實例化。 這可以跟蹤已使用的內容並在適當時調用重新加載方法。

您不應該在靜態構造函數中使用長時間運行的操作,或者至少它們不應該同步運行。 靜態構造函數隱式運行,當隱式執行占用大量時間時,它會產生有趣的錯誤:)

此外,如果您確實使用靜態構造函數,方法以及維護狀態的東西,請嘗試在完全靜態的類中隔離它們,因此在大多數情況下,它們將像單例一樣運行。 我會將實現更改為以下內容:

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

我問是否有任何方法可以查看是否調用了靜態構造函數。 我認為答案是否定的,但解決方法是創建一個可以跟蹤存儲庫的管理器。 目標是盡可能少地改變現有的類。

我對經理類的解決方案是:

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。

您可以使用單例模式,並添加一個字段,告訴您是否已創建唯一實例

實際上不需要創建單例,只需保留靜態類,並在調用應該返回它的屬性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