6

ドメイン オブジェクトを生成するために解析する必要がある巨大な XML ドキュメントがあります。

ドキュメントは巨大であるため、ユーザーが要求するたびに解析したくありませんが、最初のみ、すべてのオブジェクトをキャッシュに保存します。

public List<Product> GetXMLProducts()
{
    if (HttpRuntime.Cache.Get("ProductsXML") != null)
    {
        return (List<Product>)(HttpRuntime.Cache.Get("ProductsXML"));
    }

    string xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content\\Products.xml");
    XmlReader reader = XmlReader.Create(xmlPath);
    XDocument doc = XDocument.Load(reader);

    List<Product> productsList = new List<Product>();
    // Parsing the products element

    HttpRuntime.Cache.Insert("ProductsXML", productsList);
    return productsList;
}

この関数をシングルトンで動作させ、スレッドセーフにする最善の方法は?

オブジェクトをキャッシュに保存する方法を修正しました (コピペミスでした)

4

2 に答える 2

12

Lazy static を作成し、アプリケーションの存続期間中メモリに保持します。そして、「真の」部分を忘れないでください。それがスレッドセーフになります。

public static readonly Lazy<List<Product>> _product = new Lazy<List<Products>>(() => GetProducts(), true);

これをモデルに追加するには、プライベートにして _product.Value; を返します。

public MyModel
{
    ... bunch of methods/properties

    private static readonly Lazy<List<Product>> _products = new Lazy<List<Products>>(() => GetProducts(), true);

    private static List<Product> GetProducts()
    {
        return DsLayer.GetProducts();

    }

    public List<Product> Products { get { return _products.Value; } }
}

Lazy<> を使用してシングルトンを作成するには、このパターンを使用します。

public MyClass
{
    private static readonly Lazy<MyClass> _myClass = new Lazy<MyClass>(() => new MyClass(), true);

    private MyClass(){}

    public static MyClass Instance { get { return _myClass.Value; } }
}

更新/編集:

コンテキスト内で使用するもう 1 つの遅延パターン (つまり、セッション)

セッションに保存されている一部のモデル:

public MyModel
{
   private List<Product> _currentProducts = null;
   public List<Product> CurrentProducts 
   {
      get
      {
         return this._currentProducts ?? (_currentProducts = ProductDataLayer.GetProducts(this.CurrentCustomer));
      }
   }
}
于 2012-07-16T10:40:49.420 に答える
2

記録のために-怠惰な静的(私から+1を得るChris Gesslerの答え)は良い解決策です。この場合、常にデータをメモリに保存する必要があるためです。この回答は、特にCache(やや紛らわしいコードに対処する)の使用と、Webサイトを初期化する別の方法をもたらすことに注目しています。

これを行う従来の方法はApplication_Start、Global.asax(.cs)のハンドラーを使用することです。しかし、私は別の素晴らしい方法を示すつもりです:

Nugetを使用してWebActivatorパッケージをWebサイトに追加します。

次に、プロジェクトで作成した新しいフォルダー内の新しい.csファイルに次のコードを追加しますApp_Start

[assembly: WebActivator.PreApplicationStartMethod(typeof(*your_namespace*.MyInit), 
  "Start", Order = 0)]
namespace *your_namespace*
{

  public static class MyInit {
    public static void Start() {
      string xmlPath = HostingEnvironment.MapPath("~/Content/Products.xml");
      using(var reader = XmlReader.Create(xmlPath)) {
       XDocument doc = XDocument.Load(reader);  

       List<Product> productsList = new List<Product>();  
       // Parsing the products element

       HttpRuntime.Cache.Insert("ProductsXML", productsList); 
      }
    }
  }
}

注-Cache.Insertの正しいusing使用法、およびストリームリーダーの場合。元のコードには、他の奇妙な論理エラーとセマンティックエラーがあります。たとえば、関数の結果に割り当てようとしたり、nullの場合はキャッシュから値を返したりします。

上記のコードにいくつかの名前空間を含める必要があることにも注意してください-そして。を探してください*your_namespace*

于 2012-07-16T10:49:52.287 に答える