21

我有一个带有一些静态属性的静态类。我在静态构造函数中初始化了所有这些,但后来意识到这很浪费,我应该在需要时延迟加载每个属性。所以我转而使用该System.Lazy<T>类型来完成所有肮脏的工作,并告诉它不要使用它的任何线程安全功能,因为在我的例子中执行总是单线程的。

我结束了以下课程:

public static class Queues
{
    private static readonly Lazy<Queue> g_Parser = new Lazy<Queue>(() => new Queue(Config.ParserQueueName), false);
    private static readonly Lazy<Queue> g_Distributor = new Lazy<Queue>(() => new Queue(Config.DistributorQueueName), false);
    private static readonly Lazy<Queue> g_ConsumerAdapter = new Lazy<Queue>(() => new Queue(Config.ConsumerAdaptorQueueName), false);

    public static Queue Parser { get { return g_Parser.Value; } }
    public static Queue Distributor { get { return g_Distributor.Value; } }
    public static Queue ConsumerAdapter { get { return g_ConsumerAdapter.Value; } }
}

调试时,我注意到一条我从未见过的消息:

函数评估需要所有线程运行

在此处输入图像描述

使用前Lazy<T>,直接显示数值。现在,我需要单击带有线程图标的圆形按钮来评估惰性值。这只发生在我正在检索的属性.ValueLazy<T>。展开实际Lazy<T>对象的调试器可视化节点时,该Value属性仅显示null,没有任何消息。

该消息是什么意思,为什么在我的案例中显示?

4

5 回答 5

16

我找到了一个名为“如何:刷新观察值”的 MSDN 页面来解释它:

在调试器中计算表达式时,两个刷新图标之一可能会出现在“值”列中。一个刷新图标是一个包含两个箭头的圆圈,两个箭头朝相反的方向旋转。另一个是包含两条类似螺纹的波浪线的圆圈。

...

如果出现这两个线程,则表示由于潜在的跨线程依赖关系而未计算表达式。跨线程依赖意味着评估代码需要应用程序中的其他线程临时运行。当您处于中断模式时,应用程序中的所有线程通常都会停止。允许其他线程临时运行会对程序的状态产生意想不到的影响,并导致调试器忽略断点等事件。

如果有人可以给出它,我仍然想要一个更好的解释。这没有回答的问题包括:什么样的评估需要所有线程都运行?调试器如何识别这种情况?单击线程刷新图标时究竟会发生什么?

编辑:我想我在ILSpyLazy<T>下检查时偶然发现了答案(出于完全不同的原因)。该属性的 getter 调用了 a 。MSDN 有这样的说法:ValueDebugger.NotifyOfCrossThreadDependency()

[...] 执行函数评估通常需要冻结除执行评估的线程之外的所有线程。如果函数评估需要在多个线程上执行,就像在远程场景中可能发生的那样,评估将阻塞。NotifyOfCrossThreadDependency 通知通知调试器它必须释放线程或中止函数评估。

因此,基本上,为了防止您尝试评估某个表达式而 Visual Studio 只挂起 30 秒然后通知您“函数评估已超时”的烦人情况,代码有机会通知调试器它必须解冻评估成功的其他线程,否则评估将永远阻塞。

由于运行其他线程可能会中断您的调试会话,通常当您评估一个表达式时,所有其他线程都保持冻结状态,调试器不会自动继续并在让您跳入兔子洞之前警告您。

于 2010-12-16T12:49:13.033 回答
3

我的猜测是调试器试图通过为您加载属性来避免影响应用程序状态。

您必须记住,延迟加载仅在您引用/访问属性时发生。

现在,一般来说,您不希望调试影响应用程序的状态,否则将无法准确表示应用程序状态应该是什么(想想多线程应用程序和调试

看看海森堡

于 2010-12-16T11:26:43.483 回答
3

我为此苦苦挣扎了几个小时,发现关于要求所有线程运行的原始错误消息具有误导性。我正在从新解决方案访问现有数据库,并在新解决方案中创建新Entity Framework实体POCO和数据访问层,以访问和映射到DB.

我最初做错了两件事。我没有在我的 C# 实体中正确定义主键POCO,并且table我正在访问的在DB(它不是dbo.tablename但是edi.tablename)中有一个唯一的模式。

在我的DbContext.cs文件中,我执行了以下操作以将表映射到正确的架构下。一旦我纠正了这些事情,错误就消失了,它工作得很好。

protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
{
    base.OnModelCreating(dbModelBuilder);
    dbModelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    dbModelBuilder.Entity<TableName>().ToTable("TableName", schemaName: "EDI");
}
于 2018-02-16T20:11:45.853 回答
0

对我来说,我发现如果我有this.Configuration.LazyLoadingEnabled = false;= true;,我的 DBContext 中有没有这条线并不重要。从我对问题的阅读来看,它似乎发生了,因为一个线程正在发生并且调试器想要运行它的权限/在它触发它之前警告你。显然,在某些情况下,您甚至可以在此处根据 MUG4N 的回答允许它继续进行: Visual Studio during Debugging: The function evaluation requires all threads to run

但我发现我可以解决这个问题。

2个选项:

  1. 添加.ToList()您的Queues

    var q = db.Queues.OrderBy(e => e.Distributor).ToList();

  2. 我通过选择 Non-Public Members > _internalQuery > ObjectQuery > Results View 找到了一种解决方法。

在此处输入图像描述

于 2018-09-05T21:32:27.480 回答
0

创建一个局部变量并为其分配您要检查的值。

这将让您检查它,因为调试器不必担心访问该属性是否会干扰您的应用程序,因为它在将其分配给局部变量时已经访问了它。

于 2015-11-12T17:20:44.813 回答