public virtual bool IsNewContextOK(System.Runtime.Remoting.Contexts.Context newCtx);
public virtual bool Match(object obj);
public virtual string ToString();
}
Поскольку класс ContextAttribute не является изолированным, вполне возможно строить свои собственные пользовательские контекстные атрибуты (для этого следует получить класс, производный от ContextAttribute, и переопределить необходимые виртуальные методы). После этого вы сможете создать пользовательский программный код, отвечающий на контекстные установки.
Замечание. В этой книге не рассматриваются подробности создания пользовательских контекстов объектов, но если вы заинтересованы узнать об этом больше, прочитайте книгу
Определение контекстно-связанных объектов
Чтобы определить класс (SportsCarTS), автоматически поддерживающий потоковую безопасность, без добавления в него сложной логики синхронизации патока при реализации членов, следует взять объект, производный от ContextBoundObject, и применить атрибут [Synchronization], как показано ниже.
using System.Runtime.Remoting.Contexts;
// Этот контекстно-связанный тип будет загружен только
// в синхронизированном (т.е. многопоточном) контексте.
[Synсhronization]
public class SportsCarTS: ContextBoundObject{}
Типы с атрибутом [Synchronization] загружаются в контексте сохранения потоков. С учетом специальных контекстуальных требований типа класса MyThreadSafeObject представьте себе те проблемы, которые должны возникнуть, если размещенный объект перевести из синхронизированного контекста в несинхронизированный. Объект вдруг перестанет быть защищенным в отношении потоков и превратится в потенциального нарушителя целостности данных, поскольку другие потоки могут пытаться взаимодействовать с этим ссылочным объектом (теперь уже не сохраняющим потоки). Для гарантии того, что среда CLR не переместит объекты SportsCarTS за рамки синхронизированного контекста, достаточно взять объект, производный от ContextBoundObject.
Проверка контекста объекта
Из тех приложений, которые вы построите сами, очень немногие могут потребовать программного взаимодействия с контекстом, но вот вам пример для иллюстрации подхода, о котором идет речь. Создайте новое консольное приложение с именем ContextManipulator. Это приложение будет определить один контекстно-независимый класс (SportsCar) и один контекстно-связанный (SportsCarTS).
using System.Runtime.Remoting.Contexts; // Для типа Context.
using System.Threading; // Для типа Thread.
// Тип SportsCar не имеет специальных контекстных требований
// и будет загружен в рамках контекста, создаваемого доменом
// приложения по умолчанию.
public class SportsCar {
public SportsCar() {
// Чтение информации и вывод идентификатора контекста.
Context ctx = Thread.CurrentContext;
Console.WriteLine("{0} объект в контексте {1}", this.ToString(), ctx.ContextID);
foreach (IContextProperty itfCtxProp in ctx.ContextProperties) Console.WriteLine("-› Свойство контекста: {0}", itfCtxProp.Name);
}
}
// Тип SportsCarTS требует загрузки
// в синхронизированном контексте.
[Synchronization]
public class SportsCarTS: ContextBoundObject {
public SportsCarTS() {
// Чтение информации и вывод идентификатора контекста.
Context ctx = Thread.CurrentContext;
Console.WriteLine("{0} объект в контексте {1}", this.ToString(), ctx.ContextID);
foreach(IContextProperty itfCtxProp in ctx.ContextProperties) Console.WriteLine("-› Свойство контекста: {0}", itfCtxProp.Name);
}
}