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

これらのクラスがいくつかある場合は、ファクトリ クラスまたはマネージャ クラスを介してそれらのインスタンス化を制御してみてはどうでしょうか。これにより、使用されたものを追跡し、必要に応じてリロード メソッドを呼び出すことができます。

于 2013-01-28T15:24:28.013 に答える
1

シングルトン パターンを使用して、一意のインスタンスが既に作成されているかどうかを示すフィールドを追加できます。

実際にはシングルトンを作成する必要はありません。静的クラスを保持するだけで、データを返すプロパティゲッターが呼び出されたときにデータをロードします。

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

静的コンストラクターで長時間実行操作を使用しないでください。少なくとも、同期的に実行しないでください。静的コンストラクターは暗黙的に実行され、暗黙的な実行にかなりの時間がかかる場合、興味深いバグが発生します:)

また、状態を維持する静的コンストラクター、メソッドなどを使用する場合は、それらを完全に静的なクラスに分離して、ほとんどのシナリオでシングルトンのように動作するようにしてください。実装を次の行に沿って変更します。

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 に答える