public override void RemoveBoundBreakpoints_DbgThread(IList <DbgBoundCodeBreakpoint> boundBreakpoints)
        {
            dbgDispatcherProvider.VerifyAccess();
            var dict = CreateBreakpointDictionary(boundBreakpoints);
            var updatedBreakpoints = new List <(bool raiseMessageChanged, DbgCodeBreakpointImpl breakpoint, List <DbgBoundCodeBreakpoint> boundBreakpoints)>(dict.Count);

            lock (lockObj) {
                foreach (var kv in dict)
                {
                    var bp = kv.Key;
                    if (breakpoints.Contains(bp))
                    {
                        bool raiseMessageChanged = bp.RemoveBoundBreakpoints_DbgThread(kv.Value);
                        updatedBreakpoints.Add((raiseMessageChanged, bp, kv.Value));
                    }
                }
            }
            foreach (var info in updatedBreakpoints)
            {
                info.breakpoint.RaiseEvents_DbgThread(info.raiseMessageChanged, info.boundBreakpoints, added: false);
            }
            if (updatedBreakpoints.Count > 0)
            {
                BoundBreakpointsMessageChanged?.Invoke(this, new DbgBoundBreakpointsMessageChangedEventArgs(new ReadOnlyCollection <DbgCodeBreakpoint>(updatedBreakpoints.Where(a => a.raiseMessageChanged).Select(a => a.breakpoint).ToArray())));
            }
        }
        public override void UpdateIsDebugging_DbgThread(bool newIsDebugging)
        {
            dbgDispatcherProvider.VerifyAccess();
            List <DbgCodeBreakpointImpl> updatedBreakpoints;

            lock (lockObj) {
                if (isDebugging == newIsDebugging)
                {
                    return;
                }
                isDebugging        = newIsDebugging;
                updatedBreakpoints = new List <DbgCodeBreakpointImpl>(breakpoints.Count);
                foreach (var bp in breakpoints)
                {
                    bool updated = bp.WriteIsDebugging_DbgThread(isDebugging);
                    if (updated)
                    {
                        updatedBreakpoints.Add(bp);
                    }
                }
            }
            foreach (var bp in updatedBreakpoints)
            {
                bp.RaiseBoundBreakpointsMessageChanged_DbgThread();
            }
            if (updatedBreakpoints.Count > 0)
            {
                BoundBreakpointsMessageChanged?.Invoke(this, new DbgBoundBreakpointsMessageChangedEventArgs(new ReadOnlyCollection <DbgCodeBreakpoint>(updatedBreakpoints.ToArray())));
            }
        }
		void ModifyCore(DbgCodeBreakpointAndSettings[] settings) {
			dbgDispatcherProvider.VerifyAccess();
			List<DbgCodeBreakpointImpl>? updatedBreakpoints = null;
			var bps = new List<DbgCodeBreakpointAndOldSettings>(settings.Length);
			lock (lockObj) {
				foreach (var info in settings) {
					var bpImpl = info.Breakpoint as DbgCodeBreakpointImpl;
					Debug.Assert(!(bpImpl is null));
					if (bpImpl is null)
						continue;
					Debug.Assert(breakpoints.Contains(bpImpl));
					if (!breakpoints.Contains(bpImpl))
						continue;
					var currentSettings = bpImpl.Settings;
					if (currentSettings == info.Settings)
						continue;
					bps.Add(new DbgCodeBreakpointAndOldSettings(bpImpl, currentSettings));
					if (bpImpl.WriteSettings_DbgThread(info.Settings)) {
						if (updatedBreakpoints is null)
							updatedBreakpoints = new List<DbgCodeBreakpointImpl>(settings.Length);
						updatedBreakpoints.Add(bpImpl);
					}
				}
			}
			if (bps.Count > 0)
				BreakpointsModified?.Invoke(this, new DbgBreakpointsModifiedEventArgs(new ReadOnlyCollection<DbgCodeBreakpointAndOldSettings>(bps)));
			if (!(updatedBreakpoints is null)) {
				foreach (var bp in updatedBreakpoints)
					bp.RaiseBoundBreakpointsMessageChanged_DbgThread();
				BoundBreakpointsMessageChanged?.Invoke(this, new DbgBoundBreakpointsMessageChangedEventArgs(new ReadOnlyCollection<DbgCodeBreakpoint>(updatedBreakpoints.ToArray())));
			}
		}
		public override DbgBoundCodeBreakpoint[] AddBoundBreakpoints_DbgThread(IList<DbgBoundCodeBreakpoint> boundBreakpoints) {
			dbgDispatcherProvider.VerifyAccess();
			var dict = CreateBreakpointDictionary(boundBreakpoints);
			var updatedBreakpoints = new List<(bool raiseMessageChanged, DbgCodeBreakpointImpl breakpoint, List<DbgBoundCodeBreakpoint> boundBreakpoints)>(dict.Count);
			List<DbgBoundCodeBreakpoint>? unusedBoundBreakpoints = null;
			lock (lockObj) {
				foreach (var kv in dict) {
					var bp = kv.Key;
					if (breakpoints.Contains(bp)) {
						bool raiseMessageChanged = bp.AddBoundBreakpoints_DbgThread(kv.Value);
						updatedBreakpoints.Add((raiseMessageChanged, bp, kv.Value));
					}
					else {
						if (unusedBoundBreakpoints is null)
							unusedBoundBreakpoints = new List<DbgBoundCodeBreakpoint>();
						unusedBoundBreakpoints.AddRange(kv.Value);
					}
				}
			}
			foreach (var info in updatedBreakpoints)
				info.breakpoint.RaiseEvents_DbgThread(info.raiseMessageChanged, info.boundBreakpoints, added: true);
			if (updatedBreakpoints.Count > 0)
				BoundBreakpointsMessageChanged?.Invoke(this, new DbgBoundBreakpointsMessageChangedEventArgs(new ReadOnlyCollection<DbgCodeBreakpoint>(updatedBreakpoints.Where(a => a.raiseMessageChanged).Select(a => a.breakpoint).ToArray())));
			return unusedBoundBreakpoints?.ToArray() ?? Array.Empty<DbgBoundCodeBreakpoint>();
		}
        void AddCore(List <DbgCodeBreakpointImpl> breakpoints, List <DbgObject>?objsToClose)
        {
            dbgDispatcherProvider.VerifyAccess();
            var added = new List <DbgCodeBreakpoint>(breakpoints.Count);
            List <DbgCodeBreakpointImpl>?updatedBreakpoints = null;

            lock (lockObj) {
                foreach (var bp in breakpoints)
                {
                    Debug.Assert(!this.breakpoints.Contains(bp));
                    if (this.breakpoints.Contains(bp))
                    {
                        continue;
                    }
                    if (locationToBreakpoint.ContainsKey(bp.Location))
                    {
                        if (objsToClose is null)
                        {
                            objsToClose = new List <DbgObject>();
                        }
                        objsToClose.Add(bp);
                    }
                    else
                    {
                        added.Add(bp);
                        this.breakpoints.Add(bp);
                        locationToBreakpoint.Add(bp.Location, bp);
                        if (bp.WriteIsDebugging_DbgThread(isDebugging))
                        {
                            if (updatedBreakpoints is null)
                            {
                                updatedBreakpoints = new List <DbgCodeBreakpointImpl>(breakpoints.Count);
                            }
                            updatedBreakpoints.Add(bp);
                        }
                    }
                }
            }
            if (!(objsToClose is null))
            {
                foreach (var obj in objsToClose)
                {
                    obj.Close(dbgDispatcherProvider.Dispatcher);
                }
            }
            if (added.Count > 0)
            {
                BreakpointsChanged?.Invoke(this, new DbgCollectionChangedEventArgs <DbgCodeBreakpoint>(added, added: true));
            }
            if (!(updatedBreakpoints is null))
            {
                foreach (var bp in updatedBreakpoints)
                {
                    bp.RaiseBoundBreakpointsMessageChanged_DbgThread();
                }
                BoundBreakpointsMessageChanged?.Invoke(this, new DbgBoundBreakpointsMessageChangedEventArgs(new ReadOnlyCollection <DbgCodeBreakpoint>(updatedBreakpoints.ToArray())));
            }
        }
 internal void OnBoundBreakpointsMessageChanged_DbgThread(DbgCodeBreakpointImpl bp)
 {
     dbgDispatcherProvider.VerifyAccess();
     bp.RaiseBoundBreakpointsMessageChanged_DbgThread();
     BoundBreakpointsMessageChanged?.Invoke(this, new DbgBoundBreakpointsMessageChangedEventArgs(new ReadOnlyCollection <DbgCodeBreakpoint>(new[] { bp })));
 }