1

I read a bunch of questions and all docs at Ninject wiki, but I still doubt and ask questions to myself like "Am I doing it right?"

  1. What if I need to use controller for initialization of object? And field argument will be known only at runtime?

A) So I need something like this:

    public class MyClass : IMyInterface
    {
         private string _field;
         readonly IRepository _repo;
         public MyClass(string field, IRepository repo)
         {
             _field = field;
             _repo = repo;
         }
     }

But how to Bind it properly? Or should I forever forget about using constructor for any reason but Constructor Dependency Injection?

B) And do it like:

public class MyClass : IMyInterface
{
    private string _field;
    readonly IRepository _repo;
    public MyClass(IRepository repo)
    {
        _repo = repo;
    }
    public void Initialize(string field)
    {
        _field = field;
    }
}

I think it isn't ok to call anytime when I need object this Initialize function or I'm wrong?

According to this answers Can't combine Factory / DI and Dependency Inject (DI) "friendly" library and Is there a pattern for initializing objects created via a DI container

Use Abstract Factory if you need a short-lived object

Dependencies injected with Constructor Injection tend to be long-lived, but sometimes you need a short-lived object, or to construct the dependency based on a value known only at run-time.

C) I should do it like:

public interface IMyInterface  {  }
  public interface IMyFactory
  {
      MyClass Create(string field);
  } 
  public class MyFactory : IMyFactory
  {
      private readonly IRepository _repo;
      public MyFactory (IRepository repo)
      {
          _repo = repo;
      }
      public MyClass Create(string field)
      {
          return new MyClass(_repo, field);
      }
  }
  public class MyClass : IMyInterface
  {
      private string _field;
      readonly IRepository _repo;
      public MyClass(IRepository repo, string field)
      {
          _repo = repo;
          _field = field;
      }
  }

And if I need MyClass from another class I gonna use it like

public class OtherClass
{
    private IMyInterface _myClass;
    public OtherClass(IMyFactory factory)
    {
        _myClass = factory.Create("Something");
    }
}

Isn't it too bulky?

And my question is: What I have to use A, B or C case? And why? Or maybe something else?

Community
  • 1
  • 1
PilgrimViis
  • 1,511
  • 2
  • 17
  • 21
  • Please [edit] and split your question to multiple focused ones because it currently is too broad, and it likely will get closed in it's current form, though it's a good one... – kayess Oct 24 '16 at 07:41
  • @kayess done. I cut off half of the question. Thanks for advice – PilgrimViis Oct 24 '16 at 07:45
  • @PilgrimViis still not suited for SO unfortunately, might be an idea to read the FAQ and perhaps post these on one of the other sites. – ChrisBint Oct 24 '16 at 07:46
  • @ChrisBint, I really sorry to hear that. I reread "Don't ask" section in help center and still don't understand whats wrong with it. I provide some of my research on topic, as suggested and ask why and how I have to use some of technology in constructive tonne inviting other developers to share there knowledge. – PilgrimViis Oct 24 '16 at 07:53
  • You don't see this as subjective, open-ended, etc? – ChrisBint Oct 24 '16 at 07:54
  • @ChrisBint you definitely know more about this than I do. Even if I don't think that my question is so bad. Can you give me advice how to change my question that it'll be correct? – PilgrimViis Oct 24 '16 at 08:02
  • 1
    @PilgrimViis may I invite you to the [SOCVR](http://chat.stackoverflow.com/rooms/41570/so-close-vote-reviewers) chat room where folks could _probably_ give you hints how to edit or restructure your question. Feel free to express your current situation about this question to them. – kayess Oct 24 '16 at 08:23

3 Answers3

3

What if I need to use controller for initialization of object? And field argument will be known only at runtime?

As explained here, your application components should not require runtime data during initialization. Instead you should either:

  1. pass runtime data through method calls of the API or
  2. retrieve runtime data from specific abstractions that allow resolving runtime data.

Contrary to popular belief, abstract factories are hardly ever the right solution to this problem, because:

Instead of lowering complexity for the consumer, a factory actually increases complexity, because instead of having just a dependency on the service abstraction IService, the consumer now requires a dependency on both IService and the Abstract Factory IServiceFactory. [...] the increase in complexity can be felt instantly when unit testing such classes. Not only does this force us to test the interaction the consumer has with the service, we have to test the interaction with the factory as well.

For a detailed discussion, read this article.

Steven
  • 166,672
  • 24
  • 332
  • 435
1

The answer is, as always, it depends. Without the context it will be hard to advise.

However, there is one thing I would hesitate to do - configure to inject "pure" string to components. The string can mean thousands of things and it may be very hard to support that design later. Of course you can define that a string injected to XController will be a connection string to SQL and when injected to YController will be an authorization token, but I doubt it will be readable and easy to maintain.

That's being said I would choose option C or following approach:

    public class DescriptiveMeaningOfAClass
    {
         public string Value { get; set; }
     }

    public class MyClass : IMyInterface
    {
         private string _field;
         readonly IRepository _repo;
         public MyClass(DescriptiveMeaningOfAClass something, IRepository repo)
         {
             _field = something.Value;
             _repo = repo;
         }
     }
piotrwest
  • 2,098
  • 23
  • 35
0

Personnaly I would mix A) and C) by using ChildKernel instead of referencing directly the constructor. https://github.com/ninject/Ninject.Extensions.ChildKernel

In your factory:

var parentKernel = new StandardKernel();

var childKernel1 = new ChildKernel(parentKernel);
childKernel1.Bind<string>().ToConstant("MyRuntimeValue");
var myClass = childKernel1.Get<MyClass>();

I didn't test it but it should work.

Hachik
  • 11