下面是稍微修改过的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-10-15 20:06:59