#c_sharp #net #многопоточность #ооп
Нужно написать приложение, которые моделирует некоторые физические процессы. Будет написан некоторый класс Simulation, содержащий основные методы управления процессом моделирования (например метод Step()). Все операции в конечном итоге будут производиться над множеством (HashSet) объектов типа Atom. Над этим множеством после моделирования надо производить различные действия, к классу Simulation не относящиеся (да и перед моделированием это множество надо соорудить отдельно или откуда-то загрузить). В процессе моделирования (то есть пока будет выполняться метод Step()) множество атомов желательно как-то защитить от воздействия извне, т. е. запретить добавление / удаление атомов, изменение их свойств. Можно сделать HashSet полем класса Simulation, определив так же методы Add(Atom atom), Remove(Atom atom) и т. п. А для защиты изменения в процессе моделирования использовать if (locked) return. public class Simulation { private readonly HashSet _atoms = new HashSet (); . . . private bool locked; public bool Add(Atom atom) { if (locked) return false; if (atom == null) throw new ArgumentNullException(nameof(atom)); return _atoms.Add(atom); } public bool Remove(Atom atom) { if (locked) return false; return _atoms.Remove(atom); } public void Step(float dt) { locked = true; . . . locked = false; } . . . } Но такой подход не позволяет защитить атомы от изменения во время моделирования если ссылки на них есть где-то вне множества _atoms. Подскажите, пожалуйста, как корректно разрешить данную проблему. EDIT Атом представляет собой следующий класс: [Serializable] public class Atom { private static int _numberOfInstances; [NonSerialized] private readonly int _hashCode; public Atom() { _hashCode = Interlocked.Increment(ref _numberOfInstances); } [field: NonSerialized] internal Vector3 Acceleration { get; set; } [field: NonSerialized] internal Vector3 Displacement { get; set; } public Vector3 Position { get; set; } public Vector3 Velocity { get; set; } public override int GetHashCode() { return _hashCode; } } И защищать тут нужно свойства Position и Velocity.
Ответы
Ответ 1
Вариант 1. Точно так же, как Вы уже показали. Добавить поле locked в Atom и проверять его во всех сетерах свойств. Вариант 2. Склонировать набор атомов в новые объекты, на которые ни у кого нет ссылок, и работать с ними.Ответ 2
Если атомы - простые структуры и не содержат внутри себя ничего изменяемого, то можно сделать интерфейс только для чтения public interface IReadonlyAtom { int Id {get;} string Name{get;} } Написать реализацию атома public class Atom : IReadonlyAtom { public int Id {get;private set;} public string Name {get;set;} public Atom(int id, string name = null) { Id = id; Name = name; } // не забудьте перегрузки equals и gethashcode // если будете делать hashset с атомами } И сделать симуляцию полным владельцем коллекции атомов. То есть внешний код никак не сможет менять атомы или влиять как то ещё на них напрямую. public class Simulation { private readonly HashSet_atoms = new HashSet (); public void AddAtom(int id, string name = null) { _atoms.Add(new Atom(id, name)); } // Наружу отдаем коллекцию только для чтения с атомами только для чтения public IReadOnlyCollection Atoms => _atoms.Cast ().ToList().AsReadOnly(); } Этот вариант может пригодиться в том случае, если атомов будет настолько много, что клонирование их займет много времени \ памяти.
Комментариев нет:
Отправить комментарий