.NET 4.0 beta 2 представил IObservable и IObserver.
Каковы преимущества по сравнению с классическими событиями .NET? Разве это не решает одну и ту же проблему?
.NET 4.0 beta 2 представил IObservable и IObserver.
Каковы преимущества по сравнению с классическими событиями .NET? Разве это не решает одну и ту же проблему?
Вы можете использовать IObservable в качестве события, заменяя код, который предоставляет события со свойствами типа IObservable, но это не совсем так.
В IObservable есть две важные вещи:
Он объединяет два понятия, которые мы не знали, как унифицировать до: асинхронные операции (которые обычно возвращают одно значение) и события (которые обычно продолжаются вечно).
Это композитный. В отличие от событий CLR, IAsyncResult или INotifyCollectionChanged позволяет нам создавать определенные события из общих событий и асинхронных операций.
Вот пример, который я наткнулся на работу только сегодня днем.
В Silverlight есть некоторые эффекты, которые вы можете применить к элементу управления изображением, который нельзя применить к обычным элементам управления. Чтобы обойти эти ограничения при изменении содержимого управления, я могу дождаться обновления своего внешнего вида и сделать снимок экрана. Затем я хочу скрыть свое визуальное представление, заменить его снимок и применить визуальные эффекты к изображению. Теперь я могу применить эффекты изображения к элементу управления (если он не является интерактивным).
Эта программа была бы тривиальной, но для того, чтобы она была асинхронной. Я должен дождаться выполнения двух последовательных асинхронных операций, прежде чем я могу применить эффекты к изображению:
Вот как я решил эту проблему с помощью Rx:
// A content control is a control that displays content. That content can be
// anything at all like a string or another control. Every content control contains
// another control: a ContentPresenter. The ContentPresenter job is to generate
// a visual representation of the Content property. For example, if the Content property
// of the ContentControl is a string, the ContentPresenter creates a TextBlock and inserts
// the string into it. On the other hand if the Content property is another control the
// ContentPresenter just inserts it into the visual tree directly.
public class MyContentControl : ContentControl
{
// A subject implements both IObservable and IObserver. When IObserver methods
// are called, it forwards those calls to all of its listeners.
// As a result it has roughly the same semantics as an event that we can "raise."
private Subject<object> contentChanged = new Subject<object>();
// This is a reference to the ContentPresenter in the ContentControl template
private ContentPresenter contentPresenter;
// This is a reference to the Image control within ContentControl template. It is displayed on top of the ContentPresenter and has a cool blur effect applied to it.
private Image contentImageControl;
public MyContentControl()
{
// Using Rx we can create specific events from general events.
// In this case I want to create a specific event ("contentImageChanged") which
// gives me exactly the data I need to respond and update the UI.
var contentImageChanged =
// get the content from the content changed event
from content in contentChanged
where content != null
// Wait for the ContentPresenter visual representation to update.
// ContentPresenter is data bound to the Content property, so it will
// update momentarily.
from _ in contentPresenter.GetLayoutUpdated().Take(1)
select new WritableBitmap(contentPresenter, new TranslateTransform());
contentImageChanged.Subscribe(
contentImage =>
{
// Hide the content presenter now that we've taken a screen shot
contentPresenter.Visibility = Visibility.Collapsed;
// Set the image source of the image control to the snapshot
contentImageControl.ImageSource = contentImage;
});
}
// This method is invoked when the Content property is changed.
protected override OnContentChanged(object oldContent, object newContent)
{
// show the content presenter before taking screenshot
contentPresenter.Visibility = Visibility.Visible;
// raise the content changed "event"
contentChanged.OnNext(newContent);
base.OnContentChanged(oldContent, newContent);
}
}
Этот пример особенно прост, учитывая, что для последовательности есть только две последовательные операции. Даже в этом простом примере, хотя мы видим, что Rx добавляет ценность. Без этого мне пришлось бы использовать переменные состояния для обеспечения того, чтобы события стреляли в определенном порядке. Мне также пришлось бы написать довольно уродливый код, чтобы отсоединиться от события LayoutUpdated.
Когда вы программируете с помощью Rx, трюк состоит в том, чтобы подумать: "Какое событие я хочу, чтобы моя инфраструктура была предоставлена?" а затем создайте его. Мы подготовлены к тому, чтобы думать о событиях как о простых, управляемых событиями вещах ( "mouseover", "mouseclick", "keyup" и т.д.). Однако нет причин, по которым события не могут быть очень сложными и специфичными для вашего приложения ( "GoogleMsdnMashupStockDataArrived", "DragStarting" и "ImageContentChanged" ). Когда вы структурируете свои программы таким образом (создайте именно то, что мне нужно , а затем ответьте на него, изменив состояние), вы обнаружите, что у них меньше ошибок состояния, становятся более упорядоченными и в целом больше -describing.
Есть?:-)
Это просто расширение модели программирования на основе событий. Вы создаете что-то, что реализует IObserver, и в основном вы говорите "вот что я хочу, когда что-то в коллекции меняется". Таким образом, это просто стандартизация того, что мы все делали с событиями.
Они подталкивают его, как к большому лицу, по сравнению с шаблоном IEnumerable. IEnumerable - "pull", тогда как IObservable - "push".
Единственное преимущество, которое я вижу по прямым событиям, - это стандартизованный интерфейс. Я вижу здесь большое перекрытие с ObservableCollection (и INotifyCollectionChanged). Возможно, они пытаются принять девиз PERL с .NET: "там более чем один способ сделать это".
Я не уверен в преимуществах, но я вижу следующие отличия от классических событий .NET:
уведомления об ошибках
Классическим событиям потребуется отдельное событие для этого или класс EventArgs
со свойством Error
, которое необходимо проверить.
уведомление о конце уведомления
Классическим событиям потребуется отдельное событие для этого или EventArgs
класса с свойством Final
, которое необходимо проверить.
Вам обязательно нужно посмотреть Rx Workshop: Observables versus Events и завершите прилагаемый вызов