public Tagger(
                IThreadingContext threadingContext,
                IAsynchronousOperationListener listener,
                IForegroundNotificationService notificationService,
                TagSource tagSource,
                ITextBuffer subjectBuffer)
            {
                Contract.ThrowIfNull(subjectBuffer);

                _subjectBuffer           = subjectBuffer;
                _cancellationTokenSource = new CancellationTokenSource();

                _batchChangeNotifier = new BatchChangeNotifier(
                    threadingContext,
                    subjectBuffer, listener, notificationService, NotifyEditorNow, _cancellationTokenSource.Token);

                _tagSource = tagSource;

                _tagSource.OnTaggerAdded(this);
                _tagSource.TagsChangedForBuffer += OnTagsChangedForBuffer;
                _tagSource.Paused  += OnPaused;
                _tagSource.Resumed += OnResumed;

                // There is a many-to-one relationship between Taggers and TagSources.  i.e. one
                // tag-source can be used by many Taggers.  As such, we may be a tagger that is
                // wrapping a tag-source that has already produced tags and had sent out the
                // notifications about those tags.
                //
                // However, we still want to notify the code consuming us that we have tags to
                // display.  That way, tags can display as soon as possible when someone creates
                // a new tagger for a view/buffer.
                //
                // Note: we have to do this in the future instead of right now because we haven't
                // even been returned to the caller for them to hook up to change notifications
                // from us.
                notificationService.RegisterNotification(
                    () =>
                {
                    if (this.TagsChanged == null)
                    {
                        // don't bother reporting tags if no one is listening.
                        return;
                    }

                    var tags = _tagSource.TryGetTagIntervalTreeForBuffer(_subjectBuffer);
                    if (tags != null)
                    {
                        var collection = new NormalizedSnapshotSpanCollection(
                            tags.GetSpans(_subjectBuffer.CurrentSnapshot).Select(ts => ts.Span));
                        this.NotifyEditorNow(collection);
                    }
                },
                    listener.BeginAsyncOperation(GetType().FullName + ".ctor-ReportInitialTags"),
                    _cancellationTokenSource.Token);
            }
            private IEnumerable <ITagSpan <TTag> > GetTagsWorker(
                NormalizedSnapshotSpanCollection requestedSpans,
                bool accurate,
                CancellationToken cancellationToken)
            {
                if (requestedSpans.Count == 0)
                {
                    return(SpecializedCollections.EmptyEnumerable <ITagSpan <TTag> >());
                }

                var buffer = requestedSpans.First().Snapshot.TextBuffer;
                var tags   = accurate
                    ? _tagSource.GetAccurateTagIntervalTreeForBuffer(buffer, cancellationToken)
                    : _tagSource.TryGetTagIntervalTreeForBuffer(buffer);

                if (tags == null)
                {
                    return(SpecializedCollections.EmptyEnumerable <ITagSpan <TTag> >());
                }

                return(tags.GetIntersectingTagSpans(requestedSpans));
            }