C# Универсальный метод

Программирование на Юнити.

C# Универсальный метод

Сообщение lNORDl 22 июл 2018, 18:39

Здравствуйте! Стоит следующая задача: у меня есть собственная система событий, которая реализуется классом SignalEmitter, суть системы в том что я могу посылать некие события и подписываться\отписываться на их оброботку. Испускание события имеет такую форму - текстовый "ключ"("имя" события), и затем разного рода данные, сейчас этот метод реализован с одним единственным вариантом данных System.Object, выглядит примерно так Emit(string key, System.Object data), все работает, однако это очень не удобно так как при обработке такого события, в слушателе необходимо каждый раз полученную data приводить к какому-то реальному\нужнуму типу данных, то есть если я в data передам ссылку на врага(Enemy), то при получении события мне сначала надо будет преобразовать System.Object в Enemy - что очень не удобно, так же нет возможности удобно передать сразу несколько объектов\данных, приходится их предварительно упаковывать в какие-то обертки типа :
Синтаксис:
Используется csharp
public class EnemyHit
{
  public Enemy enemy;
  public Hit hit;

  public UpdateData(Enemy e, Hit h)
  {
    enemy = e;
    hit = h;
  }
}


То есть если я в одном событии хочу послать и Enemy и Hit, я создаю обертку EnemyHit, помещаю туда данные и потом уже одну единственную обертку передаю как все тот же System.Object: signals.Emit("enemy_hit", enemyHitData), опять же это работает - но дико не удобно.

Что я хочу в идеале: что бы при вызове метода Emit, я указывал произвольную сигнатуру метода и передавал данные соответсвующие сигнатуре, к примеру Emit<Enemy, Hit>("enemy_hit", enemy, hit); Проблема заключается в том что обработчики события(слушатели) это делегаты, что бы слушать события с разными параметрами они сами должны быть разного вида, а если сигнатура делегатов будет различаться то я не могу поместить их в один общий словарь(Dictionary) что бы сделать универсальную систему перебора, поиска и вызова необходимого делегата...

То есть сейчас список слушателей представляет собой Dictionary следующего вида Dictionary<string, List<Action<System.Object>>>, где ключ dictionary это имя события, таким образом когда надо вызвать обработчик события, я по ключу из dictionary получаю список с обработчиками List<Action<System.Object>> пробегаюсь по этому листу и вызываю все action(ы). Однако поскольку тип данных Dictionary необходимо сразу "жестко" указать я не понимаю как сделать что бы он мог содержать списки\List(ы) с разными сигнатурами, то есть что бы в одном словаре для разных событий лежали и List<Action<System.Object>> и List<Action<string, float>>... Возможно это и вовсе нериально, но что-то мне подсказывает что полиморфизм должен с этим помочь... Как вариант нужно ввести какой-то абстрактный, базовый класс, который будет общим для разного вида Action(ов), и этот базовый класс указывать как типа для dictionary, но что-то ничего путного у меня самостоятельно пока не выходит... Если кто знает как решить задачку - буду очень признателен)))

P.S. Извиняюсь за простыню))
lNORDl
UNец
 
Сообщения: 21
Зарегистрирован: 07 дек 2017, 22:21

Re: C# Универсальный метод

Сообщение 1max1 22 июл 2018, 19:00

О боже мой, возьми нормальный мессенджер и не изобретай велосипед
http://wiki.unity3d.com/index.php/CSharpMessenger
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: C# Универсальный метод

Сообщение lNORDl 22 июл 2018, 19:32

О боже мой, возьми нормальный мессенджер и не изобретай велосипед
Я ожидал такой ответ, но дело в том что мне это лишь бызовый функционал который в последствии необходимо серьезно расширить, таким образом написать свое, с возможностью свободного расширения и заточки "под себя" для меня куда профитнее )) Но пока писал эту простыню кажется нашел решение - использовать Delegate в Dictionary как базовый тип, посмотрел вашу ссылку - идея подтвердилась, там так и риализованно ))
lNORDl
UNец
 
Сообщения: 21
Зарегистрирован: 07 дек 2017, 22:21

Re: C# Универсальный метод

Сообщение lafin 30 июл 2018, 16:13

lNORDl

Если я правильно понял, ты хочешь генераторы событий и обработчики событий отделить друг от друга, поставив между ними посредника в виде SignalEmitter. Генераторы говорят ему "а ну-ка объяви событие А с такими-то данными", и посредник извещает всех подписавшихся на событие А и передаёт им эти данные.

В своей реализации ты хочешь обойти систему типов в C# и при этом продолжить пользоваться удобствами строгой типизации. Имхо, либо одно, либо другое.

Если переписать твою систему на использование стандартных событий в C#, думаю, объём кода даже не увеличится:

Синтаксис:
Используется csharp
using System;
using UnityEngine;

public class Enemy { }
public class Hit { }

public static class SignalEmitter
{
        public static event Action<Enemy, Hit> EnemyHit;
        public static event Action<Enemy, Vector3> EnemySpawned;
        public static event Action<bool> GamePaused;

        public static void OnEnemyHit(Enemy enemy, Hit hit) => EnemyHit?.Invoke(enemy, hit);
        public static void OnEnemySpawned(Enemy enemy, Vector3 position) => EnemySpawned?.Invoke(enemy, position);
        public static void OnGamePaused(bool paused) => GamePaused?.Invoke(paused);
}

public class SomeComponent : MonoBehaviour
{
        private void OnEnable()
        {
                SignalEmitter.EnemyHit += EnemyHitHandler;
                SignalEmitter.GamePaused += GamePausedHandler;
        }

        private void OnDisable()
        {
                SignalEmitter.EnemyHit -= EnemyHitHandler;
                SignalEmitter.GamePaused -= GamePausedHandler;
        }

        private void EnemyHitHandler(Enemy enemy, Hit hit) { }
        private void GamePausedHandler(bool paused) { }
}


На каждый новый тип события нужно всего две строчки: новое поле с самим событием и его сигнатурой; плюс метод, вызывающий всех подписчиков этого события.
lafin
UNец
 
Сообщения: 9
Зарегистрирован: 30 июл 2018, 15:38

Re: C# Универсальный метод

Сообщение seaman 30 июл 2018, 16:20

https://nesteruk.wordpress.com/2010/06/ ... er-part-1/
https://nesteruk.wordpress.com/2010/06/ ... er-part-2/
https://nesteruk.wordpress.com/2010/07/ ... er-part-3/
PS: ключ-строка не хорошо.
PPS: "универсальные события" - не хорошо. Лучше много частных.
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14