UWP
のネタも書きたいところですが、今回はもっと前段階の話で、interface
について書きます。
公開されているライブラリを見ると、今や、当たり前のように使われていますし、私が書く記事でも、当たり前のように使っています。
復習を兼ねて、まとめを書いてみたいと思います。
なお、書いたことは.NET全体の話ですが、全部C#
と記すので、そこはご了承ください。
リンク集
いつもの、いきなりな感じ(笑)
とりあえず、Microsoftへのリンクです。
インターフェイス (C# リファレンス) | Microsoft Docs
インターフェイス (C# プログラミング ガイド) | Microsoft Docs
あと、私の以前の記事です。
C#のinterface躍進が始まったとき
C#のinterfaceが進化を遂げたのは、C#3.0
で追加された、以下の機能*2のおかげと思っています。
リンク:C# 3.0 の概要
これらを利用して生み出されたのが、Linq
です。
これのおかげで大躍進したinterfaceが、IEnumerable<T>
です。
IEnumerableと、Linqについて
IEnumerable<T>
とは、列挙操作を定義したinterfaceで、有名なところだとList<T>
等が実装しています。
列挙操作とは、foreach
文等のループを考えると分かりやすいです。
.NET Framework2.0
では、List<T>
クラスが追加され、従来型を限定した列挙を扱う際に配列ぐらいしかなかった環境において、とても便利なクラスとして利用されていました。*3
ただ、「列挙から条件を満たすものを抽出する」場合、もう一つ列挙を作るしかなく、可読性を下げ、余計なメモリを消費*4する原因となっていました。
Linq
だと、「列挙から条件を満たすものを抽出する」という処理が、直感的に記述できます。
例:列挙から条件を満たすものを抽出する
- Linq使用
まずは、以下のソースを見て、何をやっているのか考えてみてください。
var result = students .Select(s => new {Name = s.Name, Sum = s.Math + s.Japanese + s.English}) .Where(s2 => s2.Sum >= 210); foreach(var student in result){ //上記式の戻り値は、「Name」と「Sum」を持った匿名クラスであるため、回すだけで結果が取れる }
- Linq未使用
次はこちら。やることは同じです。
List<Student> result = new List<Student>(); foreach(var student in students) { if((student.Math + student.Japanese + student.English) >= 210) { result.Add(student); } } foreach(var student in result){ //列挙中に合計が必要な場合、また計算する }
Linq使用のほうは、結果を返すために、新たなリストを生成しません。*5
しかも、「studentから名前と合計を抽出し、合計が210点以上の生徒を返す」という目的が、分かりやすくなっています。
これが、Linq
の利点と言われています。
さらに恐ろしいのは、このLinq
は、
IEnumerable
という利点があります。
List<T>
だろうが、配列だろうが、XElement
だろうが、一緒の構文で書けます。
学習コストが下がるのは、言うまでもないでしょう。
INotifyPropertyChangedについて
INotifyPropertyChanged
は、その名の通り、「プロパティの変更通知を行う」ためのインターフェイスです。
実は、上で紹介した「拡張メソッド」等とはあまりかかわりがないです。
WPF
やUWP
の、高度なデータバインドを支えるインターフェイスです。
定義は、以下の通りです。
public interface INotifyPropertyChanged { event PropertyChangedEventHandler PropertyChanged; }
よくある実装は、以下の通りです。
//イベント実行 protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } //プロパティの変更通知例 public string PersonName { get { return name; } set { if(name == value) { return; } name = value; // 値変更を通知する OnPropertyChanged("PersonName"); } }
外部からは、PropertyChanged
イベントを購読することで、「値が変わったプロパティ名」が通知されてくるので、それを使って処理する、といったところです。
が、そうやって使うことはほとんどないです。
これは、WPF
やUWP
でMVVMパターン
を使う際に利用し、画面側ライブラリで購読するようになっています。
上記の「変更通知」を行うと、Viewがそれを拾い、その名称がバインドしているコントロールのプロパティを、再度読み込んでくれます。
逆に、ユーザー入力等で値が変わった場合は、それをプロパティに通知してくれます。
余談
INotifyPropertyChanged
ですが、イベントの引数で「プロパティ名」を要求しています。
文字列なので、「参照の検索」で見つからない、タイプミス等、様々な問題が発生していました。
それを解決するために、様々な手段が存在しています。ライブラリで解決しているものが多いです。
なお、.NET Framework
レベルで解決しているものはあまりないため、利用する際は「チームで方針を決める」べきです。
StackOverflowにまとまっています。
OnPropertyChanged
の引数をExpression<Func<T>>
にする- 自作の属性を用意し、コンパイル時に自動的に変更通知の形にする
- プロパティ名受け取りに
CallerMemberName
属性を利用する
Prism
なら、BindableBase
やViewModelBase
を継承し、以下のいずれかを使いましょう。
使い分けは、場合によりけりですが、新しく作るならSetProperty
が良いと思います。(以下、定義)
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null); protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression); protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null); //使用例 public string Title { get { return _title; } private set { SetProperty(ref _title, value); } }
IObservable、IObserverについて
.NET Framework4.0
でひっそりと追加されたインターフェイスです。
Taskの陰に隠れちゃった
これは、デザインパターンの一つ、Observer
パターンの.NET実装です。
両インターフェイスは、定義としては単純で、
IObservable
イベント購読用メソッドを公開し、何か起こったら、イベントを発行するIObserver
IObservable<T>
が発行したイベントから通知を受け取る
だけです。
IObservable.Subscribe
でイベントを購読しますが、戻り値がIDisposable
であるため、若干癖があります。
とはいえ、実装例は豊富なので、問題ないと思います。
これだけだと、event
キーワードで実装できるイベントと、大して変わりません。
Reactive Extensions の登場
Reactive Extensions
は、Microsoftが作成している、ライブラリのことです。
NuGet
で入手できますが、ライブラリ名はSystem.Reactive
等になっています。
私は、いまだに使う機会に恵まれません。
これらも、拡張メソッドが利用されています。あと、ラムダ式も多用されます。*7
.NETだと、Linqを黒魔術して生まれた何か、みたいな言い方をされます(笑)
なお、.NETでの定義が非常に簡潔だったため、多言語にも簡単に移植できることから、様々な言語で実装されています。
うまく説明はできないのですが…
Linqは、連続した値(シーケンス)を扱うライブラリですが、Rxは、そのシーケンスに「時間軸」の概念を取り入れています。
「時間軸で連続した値」であることから、Linqでも扱える、的な。
…んー、まぁ、
UWP使う時に勉強します。。。(すみません)
最後に
途中で書いた、IDisposable
ですが、これも主要なインターフェイスです。
ただ、ちょっとまとめるには難しい部分が多いので、割愛しました。
個人的に思う、.NETの特徴と思える部分を選んで書きました。
C#を触れるきっかけにでもなれば。