I Know
IoC is a design principle which recommends the inversion of different kinds of controls in object-oriented design to achieve loose coupling between application classes.
But I have confilct with the following code:
static void Main(string[] args)
{
ProductService ProductService = new ProductService(new LogInDB());
ProductService.Log();
Console.ReadKey();
}
public class ProductService
{
private readonly Ilog log;
public ProductService(Ilog _log)
{
log = _log;
}
public void Log()
{
log.Log();
}
}
public interface Ilog
{
void Log();
}
public class LogInFile : Ilog
{
public void Log()
{
Console.WriteLine("Log Into File");
}
}
public class LogInDB : Ilog
{
public void Log()
{
Console.WriteLine("Log Into Data Base");
}
}
What is difference between previous and next code
In the first code I used IOC (and added product service) but next I'm using just late binding
but i see IOC not added any value
static void Main(string[] args)
{
Ilog logObj = new new LogInDB();
logObj.Log();
//I still able to using LogInDB
//Ilog logObj = new new LogInDB();
//logObj.Log();
Console.ReadKey();
}
public interface Ilog
{
void Log();
}
public class LogInFile : Ilog
{
public void Log()
{
Console.WriteLine("Log Into File");
}
}
public class LogInDB : Ilog
{
public void Log()
{
Console.WriteLine("Log Into Data Base");
}
}
This depends on your defintion of value. One advantage of IoC would be a better testability of your code, which many would argue adds a lot of value. You can easily inject mocked classes into your test code and only test the class you want to test.
By the way your example is not compileable because of the line Ilog logObj = new new LogInDB();
Related
I have the following situation.
SomeClass has a dependency on IDiagram and Diagram implements that interface. The lifetime of SomeClass is the lifetime of the Application, however the lifetime a Diagram is shorter. Say it could change when a certain button is pressed.
Since I could not find anything satisfying on this problem I came up with the pattern depicted in the Diagram below.
The Observer of the Diagram would be aware that the Diagram can change and set the correct instance when it changes.
The Observer would implement the IDiagram interface by delegating the methods of the current Diagram instance.
SomeFactory would create new Diagrams and RaiseChanged.
SomeClass would not be aware of any of this.
Is enforcing this pattern a good idea, which downsides are there? Is there a better solution to this problem?
Example code with IDependency instead of IDiagram below:
private static void Main(string[] args)
{
var transientDependency = new TransientDependency();
var dependencyObserver = new DependecyObserver(transientDependency);
var dependencyFactory = new Factory(transientDependency);
var someClass = new SomeClass(dependencyObserver);
var someOtherClass = new SomeClass(dependencyObserver);
// Note that someClass can only be used after the dependency has been created, because the Changed event has to be invoked
dependencyFactory.CreateDependency();
}
public class DependecyObserver : IDependency
{
public DependecyObserver(TransientDependency transient)
{
transient.Changed += (s, dependency) => Dependency = dependency;
}
private Dependency Dependency { get; set; }
public void SomeMethod()
{
Dependency.SomeMethod();
}
}
public class Factory
{
private TransientDependency TransientDependency { get; }
public Factory(TransientDependency transientDependency)
{
TransientDependency = transientDependency;
}
public void CreateDependency()
{
TransientDependency.RaiseChanged(new Dependency());
}
}
public class SomeClass
{
public SomeClass(IDependency dependency)
{
dependency.SomeMethod();
}
}
public class TransientDependency : TransientInstance<Dependency> { }
public abstract class TransientInstance<T>
{
public EventHandler<T> Changed;
public void RaiseChanged(T instance)
{
Changed?.Invoke(this, instance);
}
}
public class Dependency : IDependency
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public interface IDependency
{
void SomeMethod();
}
i wrote a little example to learn IoC and DI on my own.
I have one simple question:
How would you instantiate the unskilled worker in my example /
How can I swich between the following 2 inject candidates?:
kernal.Bind<IRepair>().To<Employee>();
kernal.Bind<IRepair>().To<UnskilledWorker>()
I'm a little bit confused at the moment...
class Program
{
static void Main(string[] args)
{
IWorkShop instance = GetWorkShop();
instance.StartToRepair();
Console.ReadLine();
}
private static IWorkShop GetWorkShop()
{
Ninject.IKernel kernal = new StandardKernel();
kernal.Bind<IWorkShop>().To<WorkShop>();
kernal.Bind<IRepair>().To<Employee>();
var instance = kernal.Get<IWorkShop>();
return instance;
}
}
public class WorkShop : IWorkShop
{
private IRepair _repair;
public WorkShop(IRepair repair)
{
_repair = repair;
}
public void StartToRepair()
{
_repair.RepairItNow();
}
}
interface IWorkShop
{
void StartToRepair();
}
public class Employee : IRepair
{
public void RepairItNow()
{
Console.WriteLine("Employee starts working.");
}
}
public class UnskilledWorker : IRepair
{
public void RepairItNow()
{
Console.WriteLine("Unskilled worker starts working.");
}
}
public interface IRepair
{
void RepairItNow();
}
}
If you know at compile time then you can use Ninject's contextual bindings: https://github.com/ninject/ninject/wiki/Contextual-Binding.
IKernel kernal = new StandardKernel();
kernal.Bind<IWorkShop>().To<WorkShop>();
kernal.Bind<IRepair>().To<Employee>();
kernal.Bind<IRepair>().To<UnskilledWorker>().WhenInjectedInto(typeof(IWorkShop));
var instance = kernal.Get<IWorkShop>();
return instance;
If you need to decide at runtime which dependency to instantiate you are going to have to use a factory pattern.
I have a winforms application with lot's of classes, and in every class I need to write to a log if something goes wrong.
Today I made a logger function that I initialize in every class object for using it inside.
For example I have a main logic class that have log and one more class that's running different logic that should have a log.
Today I am using:
Initialize log object in class contractor for working with it.
passing log object to the contractor.
what will be the best architecture for initialize it one time and use it in every class (Not doing it static).
My logger class:
namespace MyLogger
{
public class Logger : IMessageLogger
{
IMessageLogger _messageLogger;
public Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
public interface IMessageLogger
{
void Log(string message);
}
public class FileLogger : IMessageLogger
{
string _filePath = Environment.CurrentDirectory;
public string filePath
{
get { return _filePath; }
set { _filePath = value; }
}
public FileLogger(string filePath)
{
_filePath = filePath;
}
public void Log(string message)
{
string strFileName = Path.Combine(_filePath, String.Format("{0}{1}.log", _filePath, DateTime.Now.ToString("yyyyMMdd")));
using (StreamWriter writer = new StreamWriter(strFileName, true))
{
writer.WriteLine(DateTime.Now.ToString("[dd/MM/yyyy hh:mm:ss]") + " -> " + message);
};
}
}
public class ConsoleLogger : IMessageLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
}
I believe the best way is to implement it via DependencyInjection, you should read about it online.
But if you want a quick and easy solution, simply implement a Singleton pattern for your logger, like such -
public class Logger : IMessageLogger
{
private IMessageLogger _messageLogger;
private static Logger _instance;
public static Logger Instance
{
get
{
if (_instance == null)
{
// Pick one:
_instance = new Logger(new FileLogger("SomePath"));
_instance = new Logger(new ConsoleLogger());
}
return _instance;
}
}
private Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
And to write a log use this line -
Logger.Instance.Log("This is a log message!");
There are two sides to my answer.
The first, to get the behavior you want, make the class and methods static. This creates one instance for the lifetime of your application and you can just use FileLogger.Log wherever you need it without having to new a new FileLogger up.I am not sure why you are adverse to using a static though, so you could get the same behavior with a singleton.
The second is that you should not be writing your own logger. There are so many good, open source options available. Look at log4net, nLog or even the built in TraceSource to save yourself the effort of re-inventing the wheel.
Im writing my custom logger and injecting a log storage. I need to log requests to this storage. The problem is that this will be a circular reference between logger and storage. Is there a way to provide loose coupling in this case?
Smth like this:
public interface ILogger{
void Log(String msg);
}
public interface IStorage{
void Save(String msg);
}
public class MyLogger:ILogger{
private IStorage _storage;
public MyLogger(IStorage storage){
_storage = storage;
}
public void Log(String msg){
_storage.Save(msg);
}
}
public class MyStorage:IStorage{
private ILogger _log;
public MyStorage(ILogger logger){
_log = logger
}
public void Save(String msg){
_log.Log(msg);
//....
//send msg to a database like SQL, MongoDB, Cassandra or anything
}
}
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
Kernel.Bind<ILogger>().To<MyLogger>();
Kernel.Bind<IStorage>().To<MyStorage>();
}
}
I want to add a logger to the Windows Form Application by using Castle IOC.
I registered the logger like below:
static class Program
{
[STAThread]
static void Main()
{
IWindsorContainer container = new WindsorContainer().Install(FromAssembly.This());
container.Register(Component.For<ICommonLogger>().ImplementedBy(typeof(CommonLogger)).LifeStyle.Singleton);
container.Kernel.Resolver.AddSubResolver(new EAE_Automation.COM.LoggerResolver(container.Kernel));
}
}
Then another form of the application, I tried to use the logger as property but It comes null to the program.
namespace Test.KNXManagement
{
public partial class Test: Form
{
public ICommonLogger Logger { get; set;}
public Tunneling()
{
Logger.Info("Testing.......................");
}
}
}
I think I am missing an important point here
I also register the Form class to resolve sub dependencies.
container.Register(Classes.FromThisAssembly().BasedOn<Form>());
Then also run the application as below
Application.Run(container.Resolve<Test>());
Thats solved my problem.
Thanks everyone.
The following code, based on yours, works perfectly fine for me:
private static IWindsorContainer _container;
static Program()
{
Debug.Listeners.Add(new ConsoleTraceListener());
_container = new WindsorContainer().Install(FromAssembly.This());
_container.Register(Component.For<ICommonLogger>().ImplementedBy(typeof(CommonLogger)).LifeStyle.Singleton);
}
private static ICommonLogger Logger { get; set; }
private static void Main(string[] args)
{
Logger = _container.Resolve<ICommonLogger>();
Logger.Write("Text");
Console.ReadLine();
}
public interface ICommonLogger
{
void Write(string str);
}
public class CommonLogger : ICommonLogger
{
public void Write(string str)
{
Console.WriteLine(str);
}
}
The output of the program in the console is Text.