Dan*_*ose 14 c# .net-4.0 method-group
在更新我的UI代码(.NET 4.0应用程序中的C#)时,由于在错误的线程中执行了对UI的调用,我遇到了一个奇怪的崩溃.但是,我已经在主线程上调用了这个调用,所以崩溃没有任何意义:MainThreadDispatcher.Invoke(new Action(View.Method))
崩溃了"调用线程无法访问此对象,因为另一个线程拥有它." 在View属性上.
经过进一步调查,我找到了原因:我是通过方法组调用的.我原以为使用方法组或委托/ lambda基本上是一回事(另见这个问题和这个问题).相反,将方法组转换为委托会导致代码执行,检查值View
.这是立即完成的,即在原始(非UI)线程上,这导致崩溃.如果我使用lambda,则稍后检查属性,从而在正确的线程中完成.
至少可以说,这似乎很有趣.C#标准中有没有提到这个的地方?或者是因为需要找到正确的转换而隐含的?
这是一个测试程序.首先,直接的方式.其次,分两步,更好地说明会发生什么.为了获得额外的乐趣,我Item
在创建委托后进行修改.
namespace ConsoleApplication1 // Add a reference to WindowsBase to a standard ConsoleApplication
{
using System.Threading;
using System.Windows.Threading;
using System;
static class Program
{
static Dispatcher mainDispatcher;
static void Main()
{
mainDispatcher = Dispatcher.CurrentDispatcher;
mainDispatcher.Thread.Name = "Main thread";
var childThread = new Thread(() =>
{
Console.WriteLine("--- Method group ---");
mainDispatcher.Invoke(new Action(Item.DoSomething));
Console.WriteLine("\n--- Lambda ---");
mainDispatcher.Invoke(new Action(() => Item.DoSomething()));
Console.WriteLine("\n--- Method group (two steps) ---");
var action = new Action(Item.DoSomething);
Console.WriteLine("Invoking");
mainDispatcher.Invoke(action);
Console.WriteLine("\n--- Lambda (two steps) ---");
action = new Action(() => Item.DoSomething());
Console.WriteLine("Invoking");
mainDispatcher.Invoke(action);
Console.WriteLine("\n--- Method group (modifying Item) ---");
action = new Action(Item.DoSomething);
item = null;
mainDispatcher.Invoke(action);
item = new UIItem();
Console.WriteLine("\n--- Lambda (modifying Item) ---");
action = new Action(() => Item.DoSomething());
item = null;
Console.WriteLine("Invoking");
mainDispatcher.Invoke(action);
mainDispatcher.InvokeShutdown();
});
childThread.Name = "Child thread";
childThread.Start();
Dispatcher.Run();
}
static UIItem item = new UIItem();
static UIItem Item
{
get
{
// mainDispatcher.VerifyAccess(); // Uncomment for crash.
Console.WriteLine("UIItem: In thread: {0}", Dispatcher.CurrentDispatcher.Thread.Name);
return item;
}
}
private class UIItem
{
public void DoSomething()
{
Console.WriteLine("DoSomething: In thread: {0}", Dispatcher.CurrentDispatcher.Thread.Name);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
精简版:
namespace ConsoleApplication1 // Add a reference to WindowsBase to a standard ConsoleApplication
{
using System.Threading;
using System.Windows.Threading;
using System;
static class Program
{
static Dispatcher mainDispatcher;
static void Main()
{
mainDispatcher = Dispatcher.CurrentDispatcher;
mainDispatcher.Thread.Name = "Main thread";
var childThread = new Thread(() =>
{
Console.WriteLine("--- Method group ---");
mainDispatcher.Invoke(new Action(Item.DoSomething));
Console.WriteLine("\n--- Lambda ---");
mainDispatcher.Invoke(new Action(() => Item.DoSomething()));
mainDispatcher.InvokeShutdown();
});
childThread.Name = "Child thread";
childThread.Start();
Dispatcher.Run();
}
static UIItem item = new UIItem();
static UIItem Item
{
get
{
mainDispatcher.VerifyAccess();
Console.WriteLine("UIItem: In thread: {0}", Dispatcher.CurrentDispatcher.Thread.Name);
return item;
}
}
private class UIItem
{
public void DoSomething()
{
Console.WriteLine("DoSomething: In thread: {0}", Dispatcher.CurrentDispatcher.Thread.Name);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
无论如何,属性将被急切地访问这一事实对于方法组成员来说并不特殊;一般来说,这是成员表达式的一个特征。
\n\n实际上是 lambda 创建了特殊情况:其主体(以及属性访问)将被推迟到委托实际执行为止。
\n\n从规格来看:
\n\n\n\n7.6.4 会员访问
\n\n[...] 成员访问要么是 EI 形式,要么是 EI 形式,其中 E 是主表达式。
\n\n[...]如果 E 是属性或索引器访问,则获得属性或索引器访问的值 (\xc2\xa77.1.1),并且 E 被重新分类为值。
\n
归档时间: |
|
查看次数: |
1188 次 |
最近记录: |