У меня есть класс, который я создаю в AppDomain, используя CreateInstanceAndUnwrap. Класс содержит System.Threading.Timer.
Проблема, с которой я сталкиваюсь, заключается в том, что когда создается экземпляр класса, метод обратного вызова таймера не может видеть правильные значения экземпляра класса.
У меня есть пример кода ниже, который иллюстрирует проблему:
Библиотечный класс
using System;
using System.Threading;
namespace Library
{
[Serializable]
public class Class1
{
public Class1()
{
Started = false;
_Timer = new Timer(TimerMethod);
}
public bool Started { get; set; }
private readonly Timer _Timer;
private string _Message;
private string _TimerMessage;
public bool Start()
{
Started = true;
_Message = string.Format("Class1 says Started = {0}", Started);
_TimerMessage = "Timer message not set yet";
_Timer.Change(1000, 1000);
return Started;
}
public string GetMessage()
{
// _TimerMessage is never set by TimerMethod when this class is created within an AppDomain
return string.Format("{0}, {1}", _Message, _TimerMessage);
}
public void TimerMethod(object state)
{
// Started is always false here when this class is created within an AppDomain
_TimerMessage = string.Format("Timer says Started = {0} at {1}", Started, DateTime.Now);
}
}
}
Потребительский класс
using System;
using System.Windows.Forms;
using Library;
namespace GUI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var appDomainSetup = new AppDomainSetup
{
ApplicationName = "GUI",
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory
};
_AppDomain = AppDomain.CreateDomain(appDomainSetup.ApplicationName,
AppDomain.CurrentDomain.Evidence,
appDomainSetup);
_Class1 = _AppDomain.CreateInstanceAndUnwrap("Library", "Library.Class1") as Class1;
}
private readonly AppDomain _AppDomain;
private readonly Class1 _Class1;
private void button1_Click(object sender, EventArgs e)
{
_Class1.Start();
MessageBox.Show(_Class1.GetMessage());
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show(_Class1.GetMessage());
}
}
}
Когда выполняется код выше, GetMessage()
всегда возвращает:
Class1 говорит, что Started = True, сообщение таймера еще не установлено
Однако, если я перехожу на конструктор формы выше, чтобы создать локальный экземпляр Class1,
public Form1()
{
InitializeComponent();
_Class1 = new Class1();
}
GetMessage()
возвращает ожидаемое сообщение:
Class1 говорит, что Started = True, таймер говорит, что Started = True в 15.11.2011 12:34:06
Я провел поиск в Google, MSDN и SO, но не нашел никакой информации, которая бы конкретно касалась комбинации AppDomain, Serialization и System.Threading.Timer. Также я не смог найти никакой информации о том, почему TimerCallback не может ссылаться на локальных членов класса, который создал экземпляр Timer.