В какой-то степени это кажется чем-то, что может быть рассмотрено конвенцией, т. Е. Просто укажет, что потребитель должен считаться «только для чтения». Простой grep через исходный код должен помочь обеспечить защиту от злоумышленников.
Существует ограниченная поддержка концепции «реального единства», если вы выставите объект только как WaitHandle
. WaitHandle
экземпляры не имеют метода Set()
, так что это помогает напоминать звонящим, чтобы не путаться с ним.
Конечно, вызывающие могут по-прежнему использовать его для своего фактического типа, и в WaitHandle
есть статические методы, которые все еще позволяют манипулировать. Так что это не значит, что это 100% гарантия. Но это помогло бы (и обеспечило бы более отличительные шаблоны для grep, когда вы выполняете аудит кода).
Наконец, подход «обертки», упомянутый в комментариях, также может работать. Это наиболее надежный и является относительно распространенным шаблоном для любого вида такого рода «ограничивать доступ к членам, кроме объекта владельца».
Если вызывающие абоненты находятся в другой сборке в качестве привилегированного кода, то самый простой способ сделать это - сделать скрытый материал «внутренним» и общедоступным »общедоступным. Если они находятся в одной и той же сборке, то if вы можете поместить скрытых членов в один класс с привилегированным кодом, тогда, конечно, они могут просто быть приватными для этого класса.
Часто, однако, вы хотите инкапсулировать объект специальной доступности в качестве отдельного класса, сохраняя при этом предоставление привилегированный доступ к одному конкретному классу и ограничение доступа всеми остальными. В этом случае вы можете использовать вложенные классы для достижения этого разделения, с внешним классом, содержащим привилегированный код, и вложенным классом (классами), содержащим скрытый код.
Один из вариантов такого подхода использует дизайн базовый/суб-класс, где базовый класс имеет открытые член и суб-класс имеет скрытый код:
class A
{
public class B
{
protected ManualResetEvent _event = new ManualResetEvent(false);
public void Wait() { _event.Wait(); }
}
private class C : B
{
public void Set() { _event.Set(); }
}
public B GetAnInstanceofB() { return new C(); }
private void DoSomethingWithB(B b) { ((C)b).Set(); }
}
Теперь абоненты могут называть B.Wait()
на экземпляр возвращен, но они не могут быть отнесены к типу C
для доступа к методу Set()
. Но учтите, что код в классе A
разрешен (потому что он может отличать тип до C
).
Обратите внимание, что класс B
сам по себе не должен быть вложенным. Только C
.
Другой вариант этой темы - объявить интерфейс, содержащий только общедоступные методы, а затем иметь единственного исполнителя интерфейса. Опять же, класс реализации будет вложенным в привилегированный код, в то время как интерфейс может быть вложенным или нет.
Обратите внимание, что все это является вопросом надежности и обслуживания кода. Конечно, конечно, код может использовать отражение для проверки и доступа к любой части любого типа, который он хочет.
В конце дня вам нужно подумать о аудитории кода. Если это небольшая команда, и код полностью полностью изолирован от одного проекта, то, вероятно, достаточно просто рассказать всем, «вы можете дождаться этого, но не гадаете с этим событием». В более обширной среде может быть достаточно нескольких команд, которые работают над несколькими связанными проектами вместе, но по-прежнему в основном автономной единицей, используя WaitHandle
. Если вы пишете библиотеку, для которой вы используете широкое использование, инкапсуляция и частные члены и классы - отличный инструмент. :)
Не могли бы вы просто скомпоновать все примитивные примитивы, которые вы используете в пользовательском классе, который обладает желаемыми свойствами (который может создать только создатель экземпляра/сбросить), а затем использовать его во всем? –