internal IDisposable? AddLocalRpcTarget()

in src/StreamJsonRpc/Reflection/RpcTargetInfo.cs [188:277]


        internal IDisposable? AddLocalRpcTarget(Type exposingMembersOn, object target, JsonRpcTargetOptions? options, bool requestRevertOption)
        {
            RevertAddLocalRpcTarget? revert = requestRevertOption ? new RevertAddLocalRpcTarget(this) : null;
            options = options ?? JsonRpcTargetOptions.Default;
            IReadOnlyDictionary<string, List<MethodSignature>> mapping = GetRequestMethodToClrMethodMap(exposingMembersOn.GetTypeInfo(), options.AllowNonPublicInvocation, options.UseSingleObjectParameterDeserialization, options.ClientRequiresNamedArguments);

            lock (this.SyncObject)
            {
                foreach (KeyValuePair<string, List<MethodSignature>> item in mapping)
                {
                    string rpcMethodName = options.MethodNameTransform is not null ? options.MethodNameTransform(item.Key) : item.Key;
                    Requires.Argument(rpcMethodName is not null, nameof(options), nameof(JsonRpcTargetOptions.MethodNameTransform) + " delegate returned a value that is not a legal RPC method name.");
                    bool alreadyExists = this.targetRequestMethodToClrMethodMap.TryGetValue(rpcMethodName, out List<MethodSignatureAndTarget>? existingList);
                    if (!alreadyExists)
                    {
                        this.targetRequestMethodToClrMethodMap.Add(rpcMethodName, existingList = new List<MethodSignatureAndTarget>());
                    }

                    // Only add methods that do not have equivalent signatures to what we already have.
                    foreach (MethodSignature newMethod in item.Value)
                    {
                        if (!alreadyExists || !existingList.Any(e => e.Equals(newMethod)))
                        {
                            var signatureAndTarget = new MethodSignatureAndTarget(newMethod, target, null);
                            this.TraceLocalMethodAdded(rpcMethodName, signatureAndTarget);
                            revert?.RecordMethodAdded(rpcMethodName, signatureAndTarget);
                            existingList!.Add(signatureAndTarget);
                        }
                        else
                        {
                            if (this.TraceSource.Switch.ShouldTrace(TraceEventType.Information))
                            {
                                this.TraceSource.TraceEvent(TraceEventType.Information, (int)JsonRpc.TraceEvents.LocalMethodAdded, "Skipping local RPC method \"{0}\" -> {1} because a method with a colliding signature has already been added.", rpcMethodName, newMethod);
                            }
                        }
                    }
                }

                if (options.NotifyClientOfEvents)
                {
                    HashSet<string>? eventsDiscovered = null;
                    for (TypeInfo? t = exposingMembersOn.GetTypeInfo(); t is not null && t != typeof(object).GetTypeInfo(); t = t.BaseType?.GetTypeInfo())
                    {
                        foreach (EventInfo evt in t.DeclaredEvents)
                        {
                            if (evt.AddMethod is object && (evt.AddMethod.IsPublic || exposingMembersOn.IsInterface) && !evt.AddMethod.IsStatic)
                            {
                                if (this.eventReceivers is null)
                                {
                                    this.eventReceivers = new List<EventReceiver>();
                                }

                                if (eventsDiscovered is null)
                                {
                                    eventsDiscovered = new HashSet<string>(StringComparer.Ordinal);
                                }

                                if (!eventsDiscovered.Add(evt.Name))
                                {
                                    // Do not add the same event again. It can appear multiple times in a type hierarchy.
                                    continue;
                                }

                                if (this.TraceSource.Switch.ShouldTrace(TraceEventType.Information))
                                {
                                    this.TraceSource.TraceEvent(TraceEventType.Information, (int)JsonRpc.TraceEvents.LocalEventListenerAdded, "Listening for events from {0}.{1} to raise notification.", target.GetType().FullName, evt.Name);
                                }

                                var eventReceiver = new EventReceiver(this.jsonRpc, target, evt, options);
                                revert?.RecordEventReceiver(eventReceiver);
                                this.eventReceivers.Add(eventReceiver);
                            }
                        }
                    }
                }

                if (options.DisposeOnDisconnect)
                {
                    if (this.localTargetObjectsToDispose is null)
                    {
                        this.localTargetObjectsToDispose = new List<object>();
                    }

                    revert?.RecordObjectToDispose(target);
                    this.localTargetObjectsToDispose.Add(target);
                }
            }

            return revert;
        }