Получите реальный тип при передаче реализации интерфейса в общий метод <T>(T args) (C #) - PullRequest
0 голосов
/ 14 мая 2019

У меня есть реализация EventAggregator, которая различает типы событий и вызывает все зарегистрированные обратные вызовы с этим типом события в качестве параметра, поэтому метод публикации выглядит следующим образом:

public void Publish<T>(T args) where T : IEvent
{
     if (callbacks != null)
     {
          var callbacksByEvent = callbacks.GetCallbacksByEventType(typeof(T));
          if (callbacksByEvent != null)
          {
               foreach (var callback in callbacksByEvent)
               {
                   if (callback is Action<T>)
                   {
                        Task.Run(() => ((Action<T>)callback)(args));
                   }
               }
          }
     }
}

IEvent - это просто пустой маркерИнтерфейс для Классов Событий.Он отлично работает при передаче жестко закодированной реализации, такой как SomethingHappenedEvent : IEvent, в метод, но я хотел создать окно уведомлений, где любая реализация IEvent может быть назначена кнопкам «Да», «Нет», «Отмена», и они будутвыполняется при нажатии:

private IEvent CancelEvent;

private void Cancel()
{
     if (CancelEvent != null)
     {
         EventAggregator.Publish(CancelEvent);
     }
}

В этом сценарии callbacks.GetCallbacksByEventType(typeof(T)) возвращает значение NULL, поскольку T равно IEvent, но методы обратного вызова зарегистрированы в реальной реализации: EventAggregator.Subscribe<SomethingHappenedEvent>(OnSomethingHappened)

Если я изменю его на callbacks.GetCallbacksByEventType(args.GetType()), я получу ожидаемый список обратных вызовов, но оператор if

if(callback is Action<T>) 

по-прежнему возвращает false, поскольку T по-прежнему IEvent и методэто не Action<IEvent>, а Action<SomethingHappenedEvent>.

Итак, вопрос: как мне заставить T стать моим SomethingHappenedEvent?Я могу получить фактический тип из класса во время выполнения, используя .GetType (), так что это должно быть возможно?Я работаю на .NET Framework 4.5.

Я прочитал кучу сообщений Stackoverflow по универсальным интерфейсам и интерфейсам, но не смог найти то, что искал!Можете ли вы помочь, пожалуйста?Спасибо за чтение всего этого: D

// Редактировать: Извините, вот код для GetCallbacksByEventType метода:


        internal List<Delegate> GetCallbacksByEventType(Type eventType)
        {
            List<Delegate> callbacks;
            lock (delegateTable)
            {
                if (!delegateTable.ContainsKey(eventType))
                {
                    return null;
                }

                List<WeakDelegate> weakReferences = delegateTable[eventType];

                callbacks = new List<Delegate>(weakReferences.Count);
                for (int i = weakReferences.Count - 1; i > -1; --i)
                {
                    WeakDelegate weakReference = weakReferences[i];
                    if (weakReference.IsAlive)
                    {
                        callbacks.Add(weakReference.GetDelegate());
                    }
                    else
                    {
                        weakReferences.RemoveAt(i);
                    }
                }

                if (weakReferences.Count == 0)
                {
                    delegateTable.Remove(eventType);
                }
            }
            return callbacks;
        }

и класс WeakReference:

internal sealed class WeakDelegate
{
    readonly Type DelegateType;
    readonly MethodInfo DelegateFunction;
    readonly WeakReference DelegateTarget;


        public Delegate GetDelegate()
        {
            object target = DelegateTarget.Target;
            if (target != null)
            {
                return Delegate.CreateDelegate(DelegateType, target, DelegateFunction);
            }
            return null;
        }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...