Dependency inversion principle (DIP) states that high level modules should not depend on low level modules, both should depend on abstraction.
Abstraction should not depend on details, Details should depend upon abstraction.
Example
Without DIP
class FileLogger
{
void Handle(string error)
{
File.WriteAllText(@"C:\Error.txt", error);
}
}
internal class Customer
{
FileLogger logger = new FileLogger(); // Bad
public void Add(Database db)
{
try
{
db.Add();
}
catch (Exception error)
{
logger.Handle(error.ToString());
}
}
}
With DIP
class BetterCustomer
{
ILogger logger;
BetterCustomer(ILogger logger)
{
this.logger = logger;
}
void Add(Database db)
{
try
{
db.Add();
}
catch (Exception error)
{
logger.Handle(error.ToString());
}
}
}
class FileLogger : ILogger
{
void Handle(string error)
{
File.WriteAllText(@"C:\Error.txt", error);
}
}
interface ILogger
{
void Handle(string error);
}
// e.g. when it is used:
void UseDependencyInjectionForLogger()
{
var customer = new BetterCustomer(new FileLogger());
customer.Add(new Database());
}