2010-04-05 16 views
9

Estoy usando Ninject 2.0 para el framework .Net 3.5. Estoy teniendo dificultades con el enlace de singleton.Ninject: ¿sintaxis obligatoria de Singleton?

Tengo una clase UserInputReader que implementa IInputReader. Solo quiero que se cree una instancia de esta clase.

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

Si hago ese constructor privado, se rompe. ¿Qué estoy haciendo mal aquí?

+0

Algunas variaciones interesantes en embarazos únicos: http: // w ww.yoda.arachsys.com/csharp/singleton.html – mcliedtk

+0

Puede hacer que el constructor sea interno en lugar de privado si están en el mismo ensamblaje. Quizás eso admita un poco de seguridad si le preocupa el código de otros ensambles que acceden a ese constructor. – jpierson

+1

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

Respuesta

18

Por supuesto, se rompe si hace que el constructor sea privado. ¡No puedes llamar a constructores privados desde fuera de tu clase!

Lo que estás haciendo es exactamente lo que se supone que debes hacer. Probarlo:

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

No es necesario el campo estático para obtener el producto único ejemplo. Si está utilizando un contenedor IoC, debe obtener todas sus instancias a través del contenedor.

Si hace desea que el campo estático público (no estoy seguro si hay una buena razón para ello), puede enlazar el tipo de su valor, como este:

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

EDITAR: para especificar el IDictionary<ActionInputType, Keys> a utilizar en el constructor de UserInputReader, se puede utilizar el método de WithConstructorArgument:

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

Bien, bien. Pero el constructor de UserInputReader requiere un 'IDictionary '. ¿Cómo puedo especificar esto en Ninject? –

+0

@Rosarch: o bien crea un contenedor de marcadores alrededor del diccionario, llámalo 'IActionKeyMap' o algo así, y usa eso, o usas el método en tu comentario, o usas las instalaciones para especificar los parámetros de ctor (no recuerdo exactamente cómo :(. –

+1

Entendido: '.WithConstructorArgument (" keyMapping ",/* whatever * /);' –

0

IInputReader no declara el campo Instancia ni puede, ya que las interfaces no pueden tener campo o campo estático o incluso propiedades estáticas (o métodos estáticos).

La clase Bind no puede saber que es para encontrar el campo Instancia (a menos que use la reflexión).

Cuestiones relacionadas