Объявите интерфейс регистратора и добавьте конкретный регистратор в класс библиотеки
public interface ILogger
{
void Log(string message);
}
public class Foo
{
private ILogger _logger;
public Foo (ILogger logger)
{
_logger = logger;
}
public void DoWork ()
{
_logger.Log("Working...");
}
}
Используйте это так
var foo = new Foo(new ConsoleLogger());
var foo = new Foo(new FileLogger());
var foo = new Foo(new MsgBoxLogger());
Где все эти регистраторы реализуют интерфейс.
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
UPDATE
Как уже указал Майк Пантер, вы можете использовать делегата
public class Foo
{
private Action<string> _writeLog;
public Foo (Action<string> writeLog)
{
_writeLog = writeLog;
}
public void DoWork ()
{
_writeLog("Working...");
}
}
Вы можете назвать это так
var foo = new Foo(s => Console.WriteLine(s));
Преимущества делегатской инъекции
- Очень просто объявить
- Очень прост в использовании
- Вы можете передавать дополнительные параметры через захват переменных.
См. Статью Джона Скитса Красота замыканий для получения информации о переменном захвате.
Преимущества интерфейса впрыска
- Вы можете легко передавать параметры в регистратор через его конструктор, например, имя файла для FileLogger. Поскольку конструктор не является частью интерфейса, разные регистраторы могут иметь разные параметры конструктора.
- Вы можете легко протестировать его с помощью модульных тестов, чего нельзя сделать с помощью анонимных лямбда-выражений, поскольку нет доступа к ним из модульного теста.
- В модульных тестах классов вашей библиотеки вы можете использовать фиктивный логгер.
- Вы можете создать новый специализированный регистратор, извлекая его из существующего.
- Вы можете объявить приватные вспомогательные методы в логгере.