Передайте подписываемое действие как параметр - PullRequest
0 голосов
/ 01 июня 2018

У меня есть событие, для которого мне нужно подписать метод внутри конструктора, поэтому я хочу передать событие (Action OnNewGps) через вот так:

public AccelCalculator(SensorManager sensorManager, Action<double, double> OnNewData, Action<GPSReading> OnNewGps)
{
    this.sensorManager = sensorManager;
    sensorManager.OnNewAccelReading += CalibrateAccel;
    OnNewGps += ProcessGPS;
    OnNewDataCalculation += OnNewData;
}

Сам метод конструктора не дает мне никаких ошибок, но я не могу вызвать его из другого класса со ссылкой на экземпляр locationManager:

accelCalculator = new AccelCalculator(sensorManager, RecordAccel, locationManager.OnPositionUpdated );

Потому что:

Событие 'LocationManager.OnPositionUpdated' может появляться только в левой части + = или - =

Определено LocationManager.OnPositionUpdated:

public event Action<GPSReading> OnPositionUpdated;

1 Ответ

0 голосов
/ 01 июня 2018

Две точки, о которых мы должны помнить.

Первый

Вы можете передать это событие конструктору в качестве аргумента, но только когда вы создаете объектоставаясь в области действия класса, который содержит это событие.

см. сообщение об ошибке ниже.

Событие 'PublisherClass.Event' может появляться только нав левой части + = или - = (кроме случаев, когда они используются внутри типа 'PublisherClass')

эта ошибка возникает при попытке вызвать / передать события, находящиеся внекласс, в котором он был объявлен.

Таким образом, оставаясь внутри класса, мы можем вызывать и передавать события в качестве параметра!

Так что теперь мы знаем, еслимы создаем экземпляр подписчика (вызывающий конструктор подписчика), мы можем уверенно передать Event в конструктор. Я показал это во второй половине этого ответа.

Но это не очень хорошая практика использования событий.

Как правило (и предпочтительный способ), класс издателя никогда не должен содержать объект класса Subscriber.вместо этого класс подписчика должен содержать объект класса издателя.

Простая причина: если у издателя есть объект подписчика, он может напрямую вызывать методы подписчика (нет необходимости вызывать события для выполнения функций подписчика).

Второй

Тот факт, что в вашем коде у вас нет подписчика, созданного в издателе;повезло тебе.но тот же факт ограничит вас передачей события издателя в событие конструктора.

Что требуется слишком Becuase, если события полностью доступны вне классов. Любой внешний вызов может манипулировать им.Например, если на событие подписано несколько подписчиков, и какой-то посторонний вызов назначает ему значение null.все это подписка исчезнет.Мы можем использовать концепцию инкапсуляции, чтобы избежать этого внутри кода (манипулирующий код не должен быть публично представлен)

Лучшее, что вы можете сделать, это передать объект издателя в конструктор подписчика, и вконструктор абонента;Вы можете подписаться на желаемое событие с надлежащим методом.как показано ниже.

public delegate Object EventType();
public class PublisherClass
{
    private event EventType Event;

    public event EventType EventAccessor
    {
        add { Event += value; }
        remove { Event -= value; }
    }

    public void RaiseAnEvent()
    {
        if (Event != null) { Event(); }
    }
}

класс подписчика,

public class SubscriberClass
{
    public SubscriberClass(PublisherClass p)
    {
        p.EventAccessor += d_Event;
    }

    object d_Event()
    {
        return null;
    }
}

и другой класс, в котором вы создаете объект подписчика, а также ссылка издателя.

    static void Main(string[] args)
    {
        PublisherClass p = new PublisherClass();
        SubscriberClass s = new SubscriberClass(p);
        p.RaiseAnEvent();   
    }

Вот как вы можете передать событие как параметр (но это не очень хорошая практика, как указано выше)

независимо от того, какой параметр и тип возвращаемого значения должно принимать и возвращать событие, создайте делегат дляit.

Предположим, вы хотите метод, который возвращает object (здесь в вашем случае: Action<GPSReading>)

public delegate Object EventType();

Если ваш класс подписчика находится в процессе

теперь в классе издателя объявляют событие EventType

public delegate Object EventType();
public class PublisherClass
{
    public event EventType Event;

    public PublisherClass()
    {
        SubscriberClass d2 = new SubscriberClass(ref Event);
        if (Event != null)
        {
            Event();
        }
    }
}

Абонентский класс

public class SubscriberClass
{
    public SubscriberClass(ref EventType eve)
    {
        eve += d_Event;
    }

    object d_Event()
    {
        return null;
    }
}
...