northwood-studios/NwPluginAPI

UnregisterAllEvents does not work

Closed this issue · 0 comments

  1. Register some events
  2. Try to use UnregisterAllEvents(object plugin), and it will never complete.

Example:

Log.Info("Unregistering events");
EventManager.UnregisterAllEvents(this);
Log.Info("Done");

"Done" will never print and you may or may not get the error:

[2023-04-09 07:56:05.974 -04:00] [Error] [PluginAPI] Failed loading plugin Test Plugin,
                                 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
                                   at System.ThrowHelper.ThrowInvalidOperationException (System.ExceptionResource resource) [0x0000b] in <9577ac7a62ef43179789031239ba8798>:0
                                   at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () [0x00013] in <9577ac7a62ef43179789031239ba8798>:0
                                   at System.Collections.Generic.List`1+Enumerator[T].MoveNext () [0x0004a] in <9577ac7a62ef43179789031239ba8798>:0
                                   at System.Linq.Enumerable+SelectListIterator`2[TSource,TResult].MoveNext () [0x00029] in <351e49e2a5bf4fd6beabb458ce2255f3>:0
                                   at System.Linq.Enumerable+SelectManySingleSelectorIterator`2[TSource,TResult].MoveNext () [0x0006f] in <351e49e2a5bf4fd6beabb458ce2255f3>:0
                                   at System.Linq.Enumerable+DistinctIterator`1[TSource].MoveNext () [0x0009a] in <351e49e2a5bf4fd6beabb458ce2255f3>:0
                                   at PluginAPI.Events.EventManager.UnregisterAllEvents (System.Object plugin) [0x0007f] in <8eb2b959a7ee45a88abe21e98f866aab>:0

I only got the error sometimes.

I managed to fix this like so:

Change

public static void UnregisterAllEvents(object plugin)
{
	Type pluginType = plugin.GetType();

	foreach (var handler in Events
			.SelectMany(x =>
				x.Value.Invokers.Where(y => y.Key == pluginType))
			.SelectMany(x =>
				x.Value.Select(y => y.Target))
			.Distinct())
	{
		UnregisterEvents(pluginType, handler);
	}
}

to

public void UnregisterAllEvents(object plugin)
{
    Type pluginType = plugin.GetType();
    var handlers = EventManager.Events
                    .SelectMany(x =>
                        x.Value.Invokers.Where(y => y.Key == pluginType))
                    .SelectMany(x =>
                        x.Value.Select(y => y.Target))
                    .Distinct().ToList();

    for (int i = 0; i < handlers.Count; i++)
    {
        UnregisterEvents(pluginType, handlers[i]);
    }
}