Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to communicate from class library

I'm having some trouble conceptualizing what I'm supposed to do to facilitate communication between my class library and programs that use it -- in this case, a Windows Forms app:

// 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();
    }
}

Since there is nothing listening to the console in a winforms app, calls to log() show nothing. Is there a way to dynamically overwrite the Foo.Log method, or possibly assign a method with that signature to the Foo object that is more suitable for a forms app at runtime?

Thank you!

like image 913
Daniel Szabo Avatar asked Apr 26 '26 10:04

Daniel Szabo


1 Answers

Declare a logger interface and inject a concrete logger into the library class

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...");
    }
}

Use it like this

var foo = new Foo(new ConsoleLogger());
var foo = new Foo(new FileLogger());
var foo = new Foo(new MsgBoxLogger());

Where all these loggers implement the interface.

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

UPDATE

As Mike Panter has pointed out already, you can use a delegate

public class Foo
{
    private Action<string> _writeLog;

    public Foo (Action<string> writeLog)
    {
        _writeLog = writeLog;
    }

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

you can call it like this

var foo = new Foo(s => Console.WriteLine(s));

Advantages of the delegate injection

  • Very simple to declare
  • Very simple to use
  • You can pass additional parameters through variable capturing.

        See Jon Skeets article The Beauty of Closures for variable capturing.

Advantages of the interface injection

  • You can easily pass parameters to the logger through its constructor, like a file name for the FileLogger. Since the constructor is not part of the interface, different loggers can have different constructor parameters.
  • You can easily test it with unit tests, what you cannot do with anonymous lambda expressions, since there is no way to access them from the unit test.
  • You can use a mock logger in unit tests of your library classes.
  • You can create a new specialized logger by deriving it from an existing one.
  • You can declare private helper methods within a logger.
like image 174
Olivier Jacot-Descombes Avatar answered Apr 29 '26 02:04

Olivier Jacot-Descombes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!