【问题标题】:How to communicate from class library如何从类库进行通信
【发布时间】:2012-04-05 12:04:10
【问题描述】:

我在概念化我应该做些什么来促进我的类库和使用它的程序之间的通信时遇到了一些麻烦——在本例中,是一个 Windows 窗体应用程序:

// 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 对象,在运行时更适合表单应用程序?

谢谢!

【问题讨论】:

    标签: c# .net winforms class-library


    【解决方案1】:

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

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

    更新

    正如 Mike Panter 已经指出的那样,您可以使用委托

    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 表达式则无法做到这一点,因为无法从单元测试中访问它们。
    • 您可以在库类的单元测试中使用模拟记录器。
    • 您可以通过从现有记录器派生来创建新的专用记录器。
    • 您可以在记录器中声明私有辅助方法。

    【讨论】:

    • 注意:您可以在 Visual Studio 的输出窗口中看到 WinForms 程序的控制台输出。
    • 我添加了一个比较接口注入和委托注入的更新。
    【解决方案2】:

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

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

    【讨论】:

    • 嘿,感谢您的意见。这实际上是我认为我必须做的,但我不知道该怎么做。感谢您的发帖!
    【解决方案3】:

    根据编辑前的问题:

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

    查看Access Modifiers

    【讨论】:

    • 嗯..我认为这不是我想要做的。也许我没有问正确的问题。根据调用程序的性质,我希望能够为名为 DoWork 的 foo 对象分配一个方法,该对象的上下文适合调用它的程序。这样,只要在 Foo 对象中调用新方法,就会使用新方法。
    • @ajax81 我看不出如何调用外部方法而不将其标记为public。如果方法需要知道调用程序的上下文,请考虑将适当的参数作为参数传递给方法。
    • 啊,我明白你的意思了。我的错字 -- doWork() 现在是公开的。
    • @ajax81 正如 Olivier 在他的回答中解释的那样,您需要“注入”上下文才能获得有意义的结果。
    • @TC:太好了。感谢您抽出宝贵时间!
    猜你喜欢
    • 2019-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多