0

因此,此示例旨在尝试给出我正在尝试修改的更大系统(即 Orchard CMS)的简单视图。因此,它可能并不完美。


我正在尝试创建一个通过设置管理的日志记录系统。我遇到的问题是检索设置会导致发生日志记录。这是一个简单的例子,希望能描述这个问题:

static void Main(string[] args)
{
    string[] messages = "this is a test.  but it's going to be an issue!".Split(' ');

    Parallel.ForEach(messages, Log);

    Console.ReadLine();
}

public static void Log(string message)
{
    Console.WriteLine(GetPrefix() + message);
}

public static string GetPrefix()
{
    Log("Getting prefix!");
    return "Prefix: ";
}

这是一个明显的StackOverflowException. 但是,我该如何解决呢?在收到来自 的响应之前,我不能只禁用日志记录GetPrefix,因为我可能会错过日志。(事实上​​,在这个简单的例子中,除了第一个之外,我都错过了。)

static void Main(string[] args)
{
    string[] messages = "this is a test.  but it's going to be an issue!".Split(' ');

    Parallel.ForEach(messages, Log);

    Console.ReadLine();
}

static bool _disable = false;
public static void Log(string message)
{
    if (_disable)
    {
        return;
    }
    _disable = true;
    Console.WriteLine(GetPrefix() + message);
    _disable = false;
}

public static string GetPrefix()
{
    Log("Getting prefix!");
    return "Prefix: ";
}

(^不好。)

请注意,我目前无法控制该GetPrefix方法,只能控制该Log方法。

我不确定是否有办法解决这个问题;我可能需要将设置放在其他地方(例如配置或单独的设置文件)。但是,如果有人有想法或建议,我很乐意尝试任何事情,因为我更愿意保留现在的设置(在管理界面中)。

4

2 回答 2

1

您需要做的就是禁用当前堆栈帧。现在您可以使用反射检查堆栈帧并查看它是否已被调用,但有一个更简单的方法。每个线程都有一个堆栈帧。所以制作静态变量[ThreadStatic]

    [ThreadStatic] 静态 bool _disable = false;

这是如何运作的?

http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx

“表示静态字段的值对于每个线程都是唯一的。”

编辑:然而,仅此可能还不够。您可能想要的是每个任务一个静态变量。现在,由于任务将按线程顺序执行,在这种特殊情况下,我认为这不是问题,除非记录器可能会在不禁用的情况下失败......我不确定在这种情况下会发生什么,但它可能需要您至少将内容包装在 try/finally 块中:

static void Main() //Main(string[] args)
{
    string[] messages = "this is a test.  but it's going to be an issue!".Split(' ');

    Parallel.ForEach(messages, Log);

    Console.ReadLine();
}
[ThreadStatic]
static bool _disable = false;
public static void Log(string message)
{
    if (_disable)
    {
        return;
    }
    try {
        _disable = true;
        Console.WriteLine(GetPrefix() + message);
    } finally {
        _disable = false;
    }
}

public static string GetPrefix()
{
    Log("Getting prefix!");
    return "Prefix: ";
}

Edit II: From http://msdn.microsoft.com/en-us/library/dd460712.aspx it seems that once any of a set of tasks throws an exception outside of the task delegate, you are not guaranteed execution of any remaining tasks. It's best to handle those exceptional cases in your delegate.

于 2013-07-18T18:36:25.757 回答
0

如何将日志方法拆分为:

public static void LogWithPrefix(string message)
{
    var prefix = GetPrefix();
    Log(prefix + message);
}

public static void Log(string message)
{
    Console.WriteLine(message);
}
于 2013-07-18T17:23:24.303 回答