如何从类库中进行通信

时间:2012-03-20 23:43:31

标签: c# .net winforms class-library

我在概念化我应该做些什么以帮助我的类库和使用它的程序之间进行通信时遇到了一些麻烦 - 在这种情况下,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 个答案:

答案 0 :(得分:9)

声明一个记录器接口并将具体记录器注入库类

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

更新

正如迈克潘特已经指出的那样,你可以使用代表

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));

委托注射的优点

  • 声明非常简单
  • 使用非常简单
  • 您可以通过变量捕获传递其他参数。

请参阅Jon Skeets文章The Beauty of Closures了解变量捕获。

界面注入的优点

  • 您可以通过其构造函数轻松地将参数传递给记录器,就像FileLogger的文件名一样。由于构造函数不是接口的一部分,因此不同的记录器可以具有不同的构造函数参数。
  • 您可以使用单元测试轻松测试它,使用匿名lambda表达式无法做到这一点,因为无法从单元测试中访问它们。
  • 您可以在库类的单元测试中使用模拟记录器。
  • 您可以通过从现有记录器派生来创建新的专用记录器。
  • 您可以在记录器中声明私有帮助器方法。

答案 1 :(得分:1)

根据编辑之前的问题:

班级doWork()的方法fooprivate。你不能从你的类库之外调用它。您必须通过public方法访问它,或将其设为public

查看Access Modifiers

答案 2 :(得分:1)

或者,声明一个委托函数,并让调用者将其设置为适合上下文的内容,如下所示:

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