Контекст выполнения на IObservable с вложенными событиями - PullRequest
1 голос
/ 20 марта 2012

Контекст выполнения вложенных событий

Привет, я хотел бы узнать немного больше о контексте выполнения IObserver<T> и связанном с «вложенными событиями».

В основном, когда ясравните его с linq-to-IEnumerable, я создаю дерево выражений и выполняюсь, когда вызываю что-то вроде ToList()… и т. д. Например,

Var singleCustomer = from customer in customers
            Where customer.ID == 2
            Select customer.FirstOrDefault();

Это только выражение, которое выполняется (Я предполагаю, что когда я выполняю FirstOrDefault) ... Как это работает с миром IObservable?Я предполагаю, что это будет работать почти так же ... Мне было бы здорово получить некоторую информацию об этом ...

Это относится к моему реальному вопросу, потому что у меня есть какое-то Событие, которое является своего рода контейнером событий.

event EventHandler<ContainerEventArgs> ContainerReady;

и ContainerEventArgs будет содержать массив координат ... И мне нужно сделать там операцию, чтобы получить конкретные координаты (координаты центра), которые я ищу.Координаты центра - это то, на чем я действительно хотел бы наблюдать.Когда бы это ни изменилось, я бы хотел получить уведомление, ..

В стандартном .Net-режиме без Rx я бы сделал что-то подобное, чтобы получить событие изменения координаты для CenterCoordinate.

ContainerReady += (s,e) => {
var container = e.GetContainer();
var coordinate = new point[e.CoordinatesArrayLength]();
e.CopyCoordinatesToArray(container);
if(coordinates != null){
  var particularCoordinate = from coordinate in coordinates.where(… center coordinates…).FirstOrDefault();
if(particularCoordinate != null){
  if(CenterCoordinateUpdated != null)
     {
        CenterCoordinateUpdated(this, new CenterCoordinateUpdatedEventArgs(){
           CenterPosition = particularCoordinates;
          }
     }
}

}

Предполагая, что у меня есть какое-то второе событие вроде этого:

event EventHandler<CenterCoordinatesUpdatedEventArgs> CenterCoordinateUpdated;

Хорошо, длинная история ... сейчас Как мне справиться с этим с помощью RX?До сих пор у меня есть следующее:

public IObservable<Container> GetContainers(){
     var containerSource = Observerable.FromeEventPattern< ContainerEventArgs>(this,”ContainerReady”);
var container = from evt in containerSource.Where(x=>x.EventArgs.GetContainer != null)
select evt.GetContainers();
return container;
}

Так что это возвращает IObservable<Container>(), но, как я уже сказал, меня больше интересуют внутренние ценности ...

Я придумал это ...

public IObservable<CenterCoordinates> GetContainers(){
     var containerSource = Observerable.FromeEventPattern< ContainerEventArgs>(this,”ContainerReady”);
var container = from evt in containerSource.Where(x=>x.EventArgs.GetContainer != null)
select evt.GetContainers();
var centerCoordinate = from cc in container
             select GetCenterCoordinates(cc); //Get CenterCoordinates does the Array copy stuff
return centerCoordinate.SkipWhile(x=>x … center condition… );
}

Имеют ли смысл мои методы SkipWhile и GetCenterCoordinates?Или я в любом случае подписываюсь на любое событие (связанное с моим вступлением в IEnumerable), потому что мне нужно сначала распаковать координаты?… Когда выполняется Observable Expression-Tree?Или мне не нужно обращать внимание на это (производительность)?Есть ли лучший способ справиться с этим, используя темы или публиковать другие события?Это стиль RX?Есть предложения по улучшению?

1 Ответ

1 голос
/ 23 марта 2012

Ваше требование действительно подходит для Rx, вам просто нужно немного больше практики: -)

Позвольте мне попытаться помочь.Надеюсь, я правильно выполнил ваши требования.

Ваш запрос может быть написан так:

public IObservable<CenterCoordinates> GetContainers()
{
    var containerSource = Observerable.FromeEventPattern<ContainerEventArgs>(this, "ContainerReady");

    var query = containerSource
        .Select(ev => ev.EventArgs.GetContainer) // project event args into containers
        .Where(container => container != null) // filter null containers
        .SelectMany(container => GetCenterCoordinates(container))  // expand the stream of containers into a stream of center coordinates
        .Where(cc => .. center condition ..);  // filter only center that match a certain condition

    return query;
}

Если вы предпочитаете синтаксис запроса, вы также можете написать его так:

public IObservable<CenterCoordinates> GetContainers()
{
    var containerSource = Observerable.FromeEventPattern<ContainerEventArgs>(this, "ContainerReady");

    var query = from ev in containerSource
                let container = ev.EventArgs.GetContainer
                where container != null
                from cc in GetCenterCoordinates(container)
                where cc .. center condition ..
                select cc;

    return query;
}

Познакомьтесь с SelectMany: это один из самых важных операторов в LINQ (как LINQ для объектов, так и Rx).

И небольшое исправление: LINQ запрашивает, что мыГоворим здесь, не переведены компилятором в деревья выражений.Они переведены в цепочку методов расширения, как я показал в моем первом примере.Деревья выражений используются в более сложных сценариях (например, LINQ to SQL).

...