【问题标题】:Use external resources within an event handler在事件处理程序中使用外部资源
【发布时间】:2013-12-10 20:56:48
【问题描述】:

考虑以下程序:

class Program
{
    static void Main(string[] args)
    {
        var MyEventThrower = new EventThrower();
        var log= new List<string>();
        log.Add("Log Initialized");
        MyEventThrower.Event += LogEvent;
        MyEventThrower.RaiseEvent();
        foreach (var item in log)
        {
            Console.WriteLine(item);
        }
    }

    static void LogEvent(object sender, EventArgs e)
    {
        log.Add(sender.ToString()); //obviously doesn't work, 
                                    //but this is the sort of 
                                    //behavior I want to achieve.
    }
}

供参考:

public delegate void EventHandler(object sender, EventArgs e)

public class EventThrower
{
    public event EventHandler Event;
    protected virtual void OnEvent(EventArgs e)
    {
        if (Event!= null)
        {
            Event(this, e);
        }
    }
    public void RaiseEvent()
    {
        OnEvent(EventArgs.Empty);
    }
 }

编辑:我的问题是日志与事件处理程序不在同一个上下文中。我现在看到我可以通过使其成为静态类成员来解决这个问题。

【问题讨论】:

  • 预期的行为是什么?当我运行你的程序时,它执行了LogEvent 方法。显然是在纠正了一些错别字之后。
  • 您能够在事件处理程序中使用log.Add() 方法运行程序吗? log 在这种情况下不存在。你怎么修好它的?另外,我现在纠正一下错别字。我在 SO Question 框中输入了这个程序,我不应该这样做 =P
  • 它们在不同的线程中执行。目前还不清楚您要解决什么问题,因为除了将“log”变量设为静态类成员之外别无他法。
  • 出于某种原因,在我的客户端应用程序中,我觉得让我的外部资源成为静态类成员会阻止我做我想做的事情,但我现在意识到我错了.将其设为静态类成员即可解决问题。
  • 另一种方法是使用您需要操作的对象填充发送者和事件参数

标签: c# multithreading events


【解决方案1】:

最简单的选择是使用 lambda 来关闭列表:

var MyEventThrower = new EventThrower();
var log= new List<string>();
log.Add("Log Initialized");

MyEventThrower.Event += (sender, args) => log.Add(sender.ToString());

MyEventThrower.RaiseEvent();
foreach (var item in log)
{
    Console.WriteLine(item);
}

【讨论】:

  • 很好,我不知道你能做到这一点!我知道一定有这样的事情。但是,我意识到一个更简单的解决方案是获取日志并使其成为静态类成员,但我将来肯定会使用它。
【解决方案2】:

我不确定您是否需要将日志变量/列表用于其他任何事情,所以我假设您只需要以您设计代码的方式来促进日志记录。

我建议如下:

static void Main()
{
    var logger = new Logger();
    logger.Log("Log Initialized");

    var MyEventThrower = new EventThrower();
    MyEventThrower.Event += (sender, _) => logger.Log(Convert.ToString(sender));
    MyEventThrower.RaiseEvent();
}

public class Logger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

这让您将实现细节包装在记录器类中。您甚至可以通过创建自己的 ILogger 接口并进行不同的 Logger 实现(即一个用于文件,一个用于控制台等)来进一步扩展它。如果您只打算写入控制台,那么这可能是矫枉过正。

我喜欢使用一个类来包装实际日志记录的一件事是实现在一个位置。如果您决定希望所有日志消息都在您正在记录的消息前添加 "DEBUG:",那么您只需在一个位置进行。

与原始解决方案相比,我喜欢的另一件事是,您无需将内容添加到列表中,然后再次对其进行迭代以打印出信息。当事件被触发时,您正在这样做。这也将节省内存使用量(即在准备输出之前不要将所有日志消息保存在列表中)。如果我误解了为什么你实际上有那个字符串日志列表,那么我对此表示歉意。

【讨论】:

  • 我认为这是一个非常人为的例子,只是为了演示从事件接收器访问对象,而不是说这就是他如何使用他的程序中的日志记录。
  • 很公平。感谢您的澄清。
猜你喜欢
  • 1970-01-01
  • 2023-03-09
  • 2020-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
相关资源
最近更新 更多