Как общаться из библиотеки классов - PullRequest
2 голосов
/ 21 марта 2012

У меня возникли проблемы с концептуализацией того, что я должен делать для облегчения взаимодействия между моей библиотекой классов и программами, которые ее используют - в данном случае приложение Windows Forms:

// Class in library
class Foo()
{
    public Foo(){}

    public void DoWork()
    {
        log("Working...");
    }

    private void log( string s )
    {
        Console.Writeline(s);
    }

}

// Forms App
class Form1()
{
    public Form1()
    {
        Foo MyFoo = new Foo();
        MyFoo.DoWork();
    }
}

Снет ничего прислушивающегося к консоли в приложении winforms, вызовы log () ничего не показывают.Есть ли способ динамически перезаписать метод Foo.Log или, возможно, назначить метод с этой сигнатурой для объекта Foo, который больше подходит для приложения форм во время выполнения?

Спасибо!

Ответы [ 3 ]

9 голосов
/ 21 марта 2012

Объявите интерфейс регистратора и добавьте конкретный регистратор в класс библиотеки

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. Поскольку конструктор не является частью интерфейса, разные регистраторы могут иметь разные параметры конструктора.
  • Вы можете легко протестировать его с помощью модульных тестов, чего нельзя сделать с помощью анонимных лямбда-выражений, поскольку нет доступа к ним из модульного теста.
  • В модульных тестах классов вашей библиотеки вы можете использовать фиктивный логгер.
  • Вы можете создать новый специализированный регистратор, извлекая его из существующего.
  • Вы можете объявить приватные вспомогательные методы в логгере.
1 голос
/ 21 марта 2012

Кроме того, можно объявить делегатскую функцию и заставить вызывающую функцию установить для нее что-то подходящее для контекста, например:

public class Foo
{
    public delegate void Log(string s);

    public Log LoggingDelegate;

    public void DoWork() 
    { 
        LoggingDelegate("Working..."); 
    } 
} 

class Program
{
    private static void Log( string s ) 
    { 
        Console.WriteLine(s); 
    } 

    static void Main(string[] args)
    {
        var myFoo = new Foo();
        myFoo.LoggingDelegate = Log;
        myFoo.DoWork(); 
    }
}
1 голос
/ 21 марта 2012

На основании вопроса до его редактирования:

Метод doWork() класса foo равен private.Вы не можете вызвать его из-за пределов своей библиотеки классов.Вы должны получить к нему доступ с помощью метода public или сделать его public.

Извлечь Модификаторы доступа .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...