2011-02-09 1 views
6

J'ai un objet threadsafe qui est coûteux à créer et doit être disponible dans mon application (un Lucene.Net IndexReader).StructureMap « singleton conditionnelle » pour Lucene.Net IndexReader

L'objet peut devenir invalide, à quel point je dois le recréer (IndexReader.IsCurrent est faux, besoin d'une nouvelle instance en utilisant IndexReader.Reopen).

Je voudrais pouvoir utiliser un conteneur IoC (StructureMap) pour gérer la création de l'objet, mais je ne peux pas travailler si ce scénario est possible. Il se sent comme une sorte de cycle de vie "conditionnel singleton".

Est-ce que StructureMap fournir une telle fonctionnalité? Des suggestions alternatives?

Répondre

3

Je probablement utiliser une portée de PerRequest et ne pas retourner le IndexReader directement. Au lieu de cela, je retournerais une abstraction du IndexReader qui effectuerait une vérification sur une référence statique maintenue au niveau de la classe. Ensuite, lorsque vous accéderez à votre propriété sur shim/proxy/abstraction, elle vérifiera la référence statique (vous la ferez bien sûr sécurisée) et obtiendra le IndexReader si nécessaire avant de le renvoyer à l'utilisateur.

+0

Je suis d'accord avec casperOne. Pensez à cacher l'instance derrière une interface/façade afin de pouvoir mettre en œuvre plus facilement des stratégies telles que le regroupement d'objets. – Steven

+0

Je l'ai considéré, mais il est dommage de supprimer la possibilité de créer des objets et de gérer la durée de vie du conteneur IoC. Cela fonctionnera certainement pour moi et sera ma solution de rechange si je ne trouve rien de plus IOC centré. –

1

En fin de compte je suis allé pour un simple objet proxy qui enveloppe la IndexReader réelle et gère le Réouverture. Comme j'ai besoin d'utiliser la même instance de cette requête, j'utilise StructureMap pour en fournir une instance singleton. Code ci-dessous.

J'ai étudié la création d'un ILifecycle StructureMap personnalisé pour gérer cette situation, mais je ne suis pas allé trop loin, voir this question.

public class IndexReaderProxy 
{ 
    private IndexReader _indexReader; 
    private readonly object _indexReaderLock = new object(); 

    public IndexReaderProxy(Directory directory, bool readOnly) 
    { 
     _indexReader = IndexReader.Open(directory, readOnly); 
    } 

    public IndexReader GetCurrentIndexReader() 
    { 
     ReopenIndexReaderIfNotCurrent(); 
     return _indexReader; 
    } 

    private void ReopenIndexReaderIfNotCurrent() 
    { 
     if (_indexReader.IsCurrent()) return; 
     lock (_indexReaderLock) 
     { 
      if (_indexReader.IsCurrent()) return; 
      var newIndexReader = _indexReader.Reopen(); 
      _indexReader.Close(); 
      _indexReader = newIndexReader; 
     } 
    } 
} 

Et l'enregistrement StructureMap:

For<IndexReaderProxy>().Singleton().Use(
      new IndexReaderProxy(FSDirectory.Open(new DirectoryInfo(LuceneIndexPath)), true) 
     ); 
+0

Le contenu devrait probablement être fusionné avec la question. – casperOne

+0

Si c'est une réponse, elle devrait probablement être acceptée. Le premier –

+0

if (_indexReader.IsCurrent()) return; en dehors du verrou peut lancer une Lucene.Net.Store.AlreadyClosedException, qui devrait être interceptée. Lorsque ce thread peut entrer dans le verrou, l'IndexReader a été ouvert à nouveau sur l'index en cours. – ENOTTY

Questions connexes