2010-04-05 16 views
9

Sto usando Ninject 2.0 per il framework .Net 3.5. Sto avendo difficoltà con il binding di singleton.Ninject: sintassi del collegamento Singleton?

Ho una classe UserInputReader che implementa IInputReader. Voglio solo una istanza di questa classe per essere mai creata.

public class MasterEngineModule : NinjectModule 
    { 
     public override void Load() 
     { 
      // using this line and not the other two makes it work 
      //Bind<IInputReader>().ToMethod(context => new UserInputReader(Constants.DEFAULT_KEY_MAPPING)); 

      Bind<IInputReader>().To<UserInputReader>(); 
      Bind<UserInputReader>().ToSelf().InSingletonScope(); 
     } 
    } 

     static void Main(string[] args) 
     { 
      IKernel ninject = new StandardKernel(new MasterEngineModule()); 
      MasterEngine game = ninject.Get<MasterEngine>(); 
      game.Run(); 
     } 

public sealed class UserInputReader : IInputReader 
    { 
     public static readonly IInputReader Instance = new UserInputReader(Constants.DEFAULT_KEY_MAPPING); 

     // ... 

     public UserInputReader(IDictionary<ActionInputType, Keys> keyMapping) 
     { 
      this.keyMapping = keyMapping; 
     } 
} 

Se il costruttore viene privato, si interrompe. Cosa sto facendo di sbagliato qui?

+0

Alcune interessanti variazioni sul single: http: // w ww.yoda.arachsys.com/csharp/singleton.html – mcliedtk

+0

È possibile rendere il costruttore interno anziché privato se si trovano nello stesso assembly. Forse questo annuncio un po 'di sicurezza se ti preoccupi del codice proveniente da altri assembly che accedono a quel costruttore. – jpierson

+1

'Bind (). (). InSingletonScope()' – Jaider

risposta

18

Ovviamente si interrompe se si rende privato il costruttore. Non puoi chiamare costruttori privati ​​al di fuori della tua classe!

Quello che stai facendo è esattamente quello che dovresti fare. Provalo:

var reader1 = ninject.Get<IInputReader>(); 
var reader2 = ninject.Get<IInputReader>(); 
Assert.AreSame(reader1, reader2); 

Non è necessario il campo statico per ottenere l'istanza singleton. Se stai utilizzando un contenitore IoC, dovresti ottenere tutte le tue istanze attraverso il contenitore.

Se fai desidera che il campo statico pubblico (non so se c'è una buona ragione per questo), è possibile associare il tipo al suo valore, come questo:

Bind<UserInputReader>().ToConstant(UserInputReader.Instance); 

EDIT: per specificare il IDictionary<ActionInputType, Keys> da utilizzare nel costruttore di UserInputReader, è possibile utilizzare il metodo WithConstructorArgument:

Bind<UserInputReader>().ToSelf() 
    .WithConstructorArgument("keyMapping", Constants.DEFAULT_KEY_MAPPING) 
    .InSingletonScope(); 
+0

Ok, bello. Ma il costruttore di UserInputReader richiede un 'IDictionary '. Come posso specificarlo in Ninject? –

+0

@Rosarch: o si crea un wrapper marcatore attorno al dizionario, lo si chiama 'IActionKeyMap' o qualcosa del genere, e lo si usa, oppure si utilizza l'approccio metodo nel commento, oppure si utilizzano le funzioni per specificare i parametri del ctor (non ricordo esattamente come :(. –

+1

Ottenuto: '.WithConstructorArgument (" keyMapping ",/* qualunque * /);' –

0

IInputReader non dichiara il campo Instance né può farlo, poiché le interfacce non possono avere campo o campo statico o anche proprietà statiche (o metodi statici).

La classe Bind non può sapere che deve trovare il campo Istanza (a meno che non usi la riflessione).