我有一个应用程序显示一些数据并启动后台代理以动态更新实时图块。由于实时切片内容是在后台代理中使用从主线程填充的一些var创建的,因此我决定编写一个具有静态变量和属性的类,以便在主线程之间进行共享,这可能是一个错误的决定,但这是我认为合理的唯一一个。线程和后台代理。
现在的问题是我在主线程中写了一个变量值,但是当后台代理执行时发现这个值为null。为什么呢?
我提供了一个小例子,跳过它足以让你理解。
STATIC PART
public class Vars
{
public static IEnumerable<Contact> Contacts;
public static void Test()
{
int num = Contacts == null ? -2 : Contacts.Count();
// num is -2 here because Contacts is null !!
}
}
背景代理
public class TileAgent : ScheduledTaskAgent
{
protected override void OnInvoke(ScheduledTask task)
{
// It's necessary to use BeginInvoke to avoid Cross-thread errors
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
Vars.Test();
});
NotifyComplete();
}
}
主页
public partial class MainPage : PhoneApplicationPage
{
private void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
busyIndicator.IsRunning = false;
try
{
Vars.Contacts = e.Results
.Where(.........);
ContactResultsData.DataContext = Vars.Contacts;
// Vars.Contacts.Count() = 67 here !!!
if (Vars.GetTile() != null)
StartAgent();
}
catch (System.Exception)
{
// That's okay, no results
}
}
private void ContactResultsData_Tap(object sender, GestureEventArgs e)
{
int num = Vars.Contacts == null ? -2 : Contacts.Count();
// num = 67 here !!
}
}
我的代码出了什么问题?有没有更好的方法来完成我的任务?
考虑我在不到一个月的时间内在Windows Phone上工作,所以我确定我还在做非常糟糕的事情...
更新:
在放入正确的锁以避免来自不同线程的并发读/写之后,我决定将一个显式静态构造函数放到静态类
public class Vars
{
static Vars()
{
Debug.WriteLine("init");
}
}
每次调用后台代理时都会调用此命令!!
这解释了我将变量视为null的原因,但我不明白:为什么每次都重新创建一个静态类?
可能是因为后台代理在一个dll项目中(需要运行它)?
有没有办法创建一个只能在第一次创建的类,可以在不同的线程之间共享(在这种情况下它们是否处理?)?
答案 0 :(得分:4)
经过长时间的搜索,我终于找到了article说明:
因为我们的EvenTiles应用程序及其PeriodicTask正在运行 分开的过程,它们完全相互分离, 这意味着他们得到了他们想要的变量副本 访问,即使这些变量是在一个单独的项目中定义的。
因此,使用“简单”静态变量/属性在主应用程序和周期性任务之间共享数据是不可能的;我们必须读/写数据库或隔离存储或任何我们想要的东西。
我发现这很疯狂,但这就是故事。
答案 1 :(得分:1)
您需要同步对共享集合的访问权限。现在一个线程可以读取它(通过调用Count()
而另一个线程写入,这非常糟糕。
答案 2 :(得分:0)
我认为在您的变量中添加volatile修饰符可以解决您的问题。