IObserver<T>(IObservable<T>) vs ObservableCollection vs INotifyPropertyChanged

下面是稍微修改过的MSDN的IObservable例子。

    public struct Message
    {
        string text;

        public Message(string newText)
        {
            this.text = newText;
        }

        public string Text
        {
            get
            {
                return this.text;
            }
        }
    }

    public class Headquarters : IObservable<Message>
    {
        public Headquarters()
        {
            observers = new List<IObserver<Message>>();
        }

        private List<IObserver<Message>> observers;

        public IDisposable Subscribe(IObserver<Message> observer)
        {
            if (!observers.Contains(observer))
                observers.Add(observer);
            return new Unsubscriber(observers, observer);
        }

        private class Unsubscriber : IDisposable
        {
            private List<IObserver<Message>> _observers;
            private IObserver<Message> _observer;

            public Unsubscriber(List<IObserver<Message>> observers, IObserver<Message> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }

            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }

        public void SendMessage(Nullable<Message> loc)
        {
            foreach (var observer in observers)
            {
                if (!loc.HasValue)
                    observer.OnError(new MessageUnknownException());
                else
                    observer.OnNext(loc.Value);
            }
        }

        public void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
                if (observers.Contains(observer))
                    observer.OnCompleted();

            observers.Clear();
        }
    }

    public class MessageUnknownException : Exception
    {
        internal MessageUnknownException()
        {
        }
    }

    public class Inspector : IObserver<Message>
    {
        private IDisposable unsubscriber;
        private string instName;

        public Inspector(string name)
        {
            this.instName = name;
        }

        public string Name
        {
            get
            {
                return this.instName;
            }
        }

        public virtual void Subscribe(IObservable<Message> provider)
        {
            if (provider != null)
                unsubscriber = provider.Subscribe(this);
        }

        public virtual void OnCompleted()
        {
            Console.WriteLine("The headquarters has completed transmitting data to {0}.", this.Name);
            this.Unsubscribe();
        }

        public virtual void OnError(Exception e)
        {
            Console.WriteLine("{0}: Cannot get message from headquarters.", this.Name);
        }

        public virtual void OnNext(Message value)
        {
            Console.WriteLine("{1}: Message I got from headquarters: {0}", value.Text, this.Name);
        }

        public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Inspector inspector1 = new Inspector("Greg Lestrade");
            Inspector inspector2 = new Inspector("Sherlock Holmes");

            Headquarters headquarters = new Headquarters();

            inspector1.Subscribe(headquarters);
            inspector2.Subscribe(headquarters);

            headquarters.SendMessage(new Message("Catch Moriarty!"));
            headquarters.EndTransmission();

            Console.ReadKey();
        }
    }

下面是一个用ObservableCollection实现自动保存功能的Collection.

    /// <summary>
    /// Keep objects in the collection mirrored on a disk storage device, and support restore of collection from save disk file
    /// </summary>
    /// <typeparam name="T">Type of object in the collection</typeparam>
    public class AutoSaveCollection<T> : ObservableCollection<T>, IDisposable
    {
        private string fileName;

        private IFormatter formatter = new BinaryFormatter();

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="fileName">Full filename to back the collection on disk</param>
        /// <param name="restoreFromFile">Restore collection from file</param>
        public AutoSaveCollection(string fileName, bool restoreFromFile)
            : base()
        {
            this.fileName = fileName;
            if (restoreFromFile)
            {
                if (File.Exists(this.fileName))
                {
                    Restore();
                }
            }
            else
            {
                if (File.Exists(this.fileName))
                {
                    File.Delete(this.fileName);
                }
            }

            base.CollectionChanged += observableCollection_CollectionChanged;
        }

        /// <summary>
        /// This event handler is triggered whenever the observable collection has been changed.  Trigger save to disk based on the change
        /// </summary>
        /// <param name="sender">self</param>
        /// <param name="e">change type</param>
        private void observableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewItems != null)
                    {
                        SaveNew(e.NewItems.ToArray<T>());
                    }
                    break;
                case NotifyCollectionChangedAction.Move:
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Replace:
                case NotifyCollectionChangedAction.Reset:
                    SaveAll();
                    break;
            }
        }

        /// <summary>
        /// Discard the disk file.
        /// </summary>
        public void Discard()
        {
            base.Clear();
            if (File.Exists(this.fileName))
            {
                File.Delete(this.fileName);
            }
        }

        /// <summary>
        /// Save everything stored in the collection to disk again (eg when collection item has been removed or when exiting)
        /// </summary>
        public void SaveAll()
        {
            string backupFileName = null;
            try
            {
                backupFileName = Helpers.RenameIfExists(this.fileName);
                using (FileStream stream = new FileStream(this.fileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read))
                {
                    foreach (T item in this)
                    {
                        this.formatter.Serialize(stream, item);
                    }
                }

                try
                {
                    if (File.Exists(backupFileName))
                    {
                        File.Delete(backupFileName);
                    }
                }
                catch (IOException ex)
                {
                    Logger.LogException(ex, "I/O failure");
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex, "Failed to save objects", this.fileName);

                if (!string.IsNullOrEmpty(backupFileName) && File.Exists(backupFileName))
                {
                    File.Move(backupFileName, fileName);
                }

                throw;
            }
        }

        /// <summary>
        /// Save new items directly to disk (don‘t bother add them to collection (to save memory))
        /// </summary>
        /// <param name="newItems"></param>
        public void SaveNew(params T[] newItems)
        {
            SaveNew((IEnumerable<T>)newItems);
        }

        private void SaveNew(IEnumerable<T> newItems)
        {
            try
            {
                using (FileStream stream = new FileStream(this.fileName, FileMode.Append, FileAccess.Write, FileShare.Read))
                {
                    foreach (T item in newItems)
                    {
                        this.formatter.Serialize(stream, item);
                    }
                }
                return;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex, "Exception adding data to file", this.fileName);
            }

            SaveAll();
        }

        /// <summary>
        /// Restore saved collection from disk file
        /// </summary>
        public void Restore()
        {
            Stream stream = null;
            try
            {
                if (!File.Exists(this.fileName))
                {
                    return;
                }

                base.Clear();

                using (stream = new FileStream(this.fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    while (stream.Position < stream.Length)
                    {
                        T item = (T)this.formatter.Deserialize(stream);
                        if (item != null)
                        {
                            base.Add(item);
                        }
                    }
                }
            }
            catch (IOException ex)
            {
                Logger.LogException(ex, "Exception when restoring checkpoint", fileName);
            }
        }

        /// <summary>
        /// On dispose, save everything in the collection to disk at once.
        /// </summary>
        void IDisposable.Dispose()
        {
            base.CollectionChanged -= observableCollection_CollectionChanged;
            if (base.Count > 0)
            {
                SaveAll();
            }
        }
    }

INotifyPropertyChanged只是一个接口,主要用于当类的属性值发生改变的时候通知,貌似在WPF用的比较多。

public class UserNPC:INotifyPropertyChanged
{
    private string name;
    public string Name {
        get { return name; }
        set { name = value; onPropertyChanged(this, "Name"); }
    }
    public int grade;
    public int Grade {
        get { return grade; }
        set { grade = value; onPropertyChanged(this, "Grade"); }
    }

    // Declare the PropertyChanged event
    public event PropertyChangedEventHandler PropertyChanged;

    // OnPropertyChanged will raise the PropertyChanged event passing the
    // source property that is being updated.
    private void onPropertyChanged(object sender, string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
        }
    }
}

IObserver<T>&IObservable<T>是对设计模式的实现跟总结,ObservableCollection跟INotifyPropertyChanged通过事件来通知。

时间: 2024-08-02 03:15:39

IObserver<T>(IObservable<T>) vs ObservableCollection vs INotifyPropertyChanged的相关文章

001.Reactive Extensions

基本概念 The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators. Reactive Extensions represents all these data sequences as observable sequences. An applicat

WP8.1 侧边滑动Item

效果图 我看ios 和安卓上有好多类似的Item的效果,UWP上有微软官方的库,其中也有类似得效果,看样子WP8.1没有啊,顺便我的程序也是需要,我也就仿了一个. 具体思路是: 触摸控制GRId在CANvas的相对位置.滑动这个Item时候,其他已经滑动完成的ITEM关闭.只能有一个打开. 实现这个效果,至少需要以下知识点: Canvsa基础知识 触控基础知识 ObservableCollection<T>基本使用 INotifyPropertyChanged接口基本使用 咱也不罗嗦 开始 先

C#游戏框架uFrame

C#游戏框架uFrame兼谈游戏架构设计 c#语言规范 阅读目录 1.概览 2.基本概念 3.依赖注入 4.Manager of Managers 5.利用UniRX实现响应式编程 6.研究总结 回到目录 1.概览 uFrame是提供给Unity3D开发者使用的一个框架插件,它本身模仿了MVVM这种架构模式(事实上并不包含Model部分,且多出了Controller部分).因为用于Unity3D,所以它向开发者提供了一套基于Editor的可视化编辑工具,可以用来管理代码结构等.需要指出的是它的一

重温Observer模式--热水器·改

在 C#中的委托和事件 一文的后半部分,我向大家讲述了Observer(观察者)模式,并使用委托和事件实现了这个模式.实际上,不使用委托和事件,一样可以实现Observer模式.在本文中,我将使用GOF的经典方式,再次实现一遍Observer模式,同时将讲述在 C#中的委托和事件 一文中没有提及的推模式(Push)和拉模式(Pull). 设计思想概述 在 C#中的委托和事件 一文后半部分中我已经较详细的讲述了Observer设计模式的思想,所以这里仅简单的提及一下.Observer设计模式中实际

WPF(6):概念绑定

WPF 的体系结构,标记扩展,依赖属性,逻辑树/可视化树,布局,转换等.今天,我们将讨论 WPF 最重要的一部分——绑定.WPF 带来了优秀的数据绑定方式,可以让我们绑定数据对象,这样每次对象发生更改都能引发对应的改变.数据绑定最主要的目的是确保 UI 上的改变总是自动和内部的对象结构同步.在进一步讨论前,我们先看一下我们已经讨论过的问题. 数据绑定技术是在 WPF 技术之前就出现了.在 ASP.NET 中,我们通过绑定数据元素来渲染控件中适当的数据.我们通常传入一个 DataTable 并且绑

玩转INotifyPropertyChanged和ObservableCollection

本文的代码都是基于WPF的,对于Silverlight,这些技术也同样适用. (一)INotifyPropertyChanged的使用场合 先写一个最简单的数据绑定,每次点击Button后,TextBlock的值都会自增1. 效果图如下所示: 这里使用了MVVM模式,并把Click事件抽象为了Command. 代码下载:WpfApplication4_1.zip 观察上面的代码,注意到几个细节: 1. UserName和Age属性作为ViewModel的两个属性,因为Age递增是基于绑定实现的,

属性更改通知(INotifyPropertyChanged)——针对ObservableCollection

问题 在开发webform中,wpf中的ObservableCollection<T>,MSDN中说,在添加项,移除项时此集合通知控件,我们知道对一个集合的操作是CURD但是恰恰没有Update的时候提供集合通知,也就是说当我Update的时候,虽然"集合内容"已被修改,但是"控件"却没有实现同步更新INotifyPropertyChanged提供了解决方案. 方案1:INotifyPropertyChanged 传统方式,实现接口INotifyProp

C# 通知机制 IObserver&lt;T&gt; 和 IObservable&lt;T&gt;

class Program { public static void Main() { // Define a provider and two observers. LocationTracker provider = new LocationTracker(); LocationReporter reporter1 = new LocationReporter("FixedGPS"); reporter1.Subscribe(provider); LocationReporter

Silverlight实用窍门系列:47.Silverlight中元素到元素的绑定,以及ObservableCollection和List的使用区别

问题一:在某一些情况下,我们使用MVVM模式的时候,对于某一个字段(AgeField)需要在前台的很多个控件(A.B.C.D.E)进行绑定,但是如何能够让我们后台字段名改变的时候能够非常方便的改变所有使用了这个字段的控件呢? 回答:使用Element to Element Binding,将AgeFiled绑定到A控件,然后再让B.C.D.E控件绑定A控件的使用AgeField字段的属性. 例如:字段(AgeField)的数据是年龄大小,A.B.C.D.E控件分别是Ellipse.Label.S