IQueryable な Twitter のタイムライン クラスと LINQ プロバイダー
「C# Advent Calendar 2014」の12日目の記事。
以前、「[C#][式木][LINQ] Hokuriku.NET C# 勉強会『C# 式木』(2014-10-26、金沢) のスライド公開」で、IQueryable な LINQ について解説した。
本記事では、その中の IQueryable なサンプルを補足する。
IQueryable な LINQ の中はどのようになっているのだろうか。
試しに少し実装してみることで、LINQ について理解を深めよう。
IEnumerable と IQueryable
「[C#][ラムダ式][LINQ][式木] 匿名メソッドとラムダ式の違い」で紹介したように、匿名メソッドは delegate としてしか使えないが、ラムダ式は delegate としても式木としても使うことができる。
※ [C#][ラムダ式][式木] Expression として扱えるラムダ式と扱えないラムダ式」で紹介したように、ラムダ式であれば必ず式木として使うことができるわけではない。
※ クエリ構文は、「式木として扱えるラムダ式」の糖衣構文。つまり、式木を扱うことになる。
参考: LINQ でのクエリ構文とメソッド構文 (C#) - MSDN
LINQ の中には、次の二つの種類のライブラリがある。
LINQ to Objects などは前者で処理され、LINQ to SQL、LINQ to Entities などは後者だ。
IQueryable なものを作ってみよう
今回は、IQueryable な Twitter のライムライン クラスを作ろうとしてみる。
先ずは IQueryable なクラス QueryableTweets。
※ IQueryable なだけでは OrderBy の対象となることができないので、ここでは IQueryable からの派生で OrderBy 可能な IOrderedQueryable を用いることにする。
// QueryableTweets.cs using System.Linq; // IOrderedQueryable<string> な QueryableTweets // まだ IOrderedQueryable インタフェイスを実装してないのでコンパイル エラー public class QueryableTweets<TElement> : IOrderedQueryable<TElement> {}
ここから、Visual Studio でインタフェイスの実装を行うと次のようになる。
// QueryableTweets.cs using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; // IOrderedQueryable<string> な QueryableTweets // Visual Studio でインタフェイスを実装した直後 public class QueryableTweets<TElement> : IOrderedQueryable<TElement> { public Type ElementType { get { throw new NotImplementedException(); } } public Expression Expression { get { throw new NotImplementedException(); } } public IQueryProvider Provider { get { throw new NotImplementedException(); } } public IEnumerator<TElement> GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } }
IQueryable は IEumerable から派生している。そのため IEumerable のメンバーである GetEnumerator() を実装する必要がある。
その他に、ElementType、Expression、Provider というプロパティを実装しなければならない。
実装を進めていこう。このクラスの実装はそれほど大変ではない。
Provider プロパティのために IQueryProvider インタフェイスを持つクラスを用意する必要があるが、ここでは、それを仮に TwitterQueryProvider クラスとしておこう。 TwitterQueryProvider クラスは後述する。
// QueryableTweets.cs using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; // IOrderedQueryable<string> な QueryableTweets public class QueryableTweets<TElement> : IOrderedQueryable<TElement> { public Type ElementType { get { return typeof(TElement); } } public Expression Expression { get; set; } public IQueryProvider Provider { get; set; } public QueryableTweets() { Provider = new TwitterQueryProvider(); // IQueryProvider インタフェイスを実装したクラス。後述。 Expression = Expression.Constant(this); } public IEnumerator<TElement> GetEnumerator() { return ((IEnumerable<TElement>)Provider.Execute(Expression)).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
IQueryProvider なもの (LINQ プロバイダー) を作ろうとしてみよう
続いて、上記 QueryableTweets で使うための、IQueryProvider なものの実装だ。
これは、LINQ プロバイダーと呼ばれるもので、式木としてのクエリーを解釈する。
こちらの実装は大変だ。
クラス名を TwitterQueryProvider として、IQueryProvider を実装していこう。
// TwitterQueryProvider.cs using System.Linq; // LINQ プロバイダーの実験用 // まだ IQueryProvider インタフェイスを実装してないのでコンパイル エラー public class TwitterQueryProvider : IQueryProvider {}
ここから、Visual Studio でインタフェイスの実装を行うと次のようになる。
// TwitterQueryProvider.cs using System; using System.Linq; using System.Linq.Expressions; // LINQ プロバイダーの実験用 // Visual Studio でインタフェイスを実装した直後 public class TwitterQueryProvider : IQueryProvider { public IQueryable CreateQuery(Expression expression) { throw new NotImplementedException(); } public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { throw new NotImplementedException(); } public object Execute(Expression expression) { throw new NotImplementedException(); } public TResult Execute<TResult>(Expression expression) { throw new NotImplementedException(); } }
少し実装を進めてみる。
// TwitterQueryProvider.cs using System; using System.Linq; using System.Linq.Expressions; // LINQ プロバイダーの実験用 public class TwitterQueryProvider : IQueryProvider { IQueryable IQueryProvider.CreateQuery(Expression expression) { return null; } public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { return new QueryableTweets<TElement> { Provider = this, Expression = expression }; } public TResult Execute<TResult>(Expression expression) { return default(TResult); } public object Execute(Expression expression) { // ここで式木を解釈して、コレクションを作って返す return null; // とりあえずは仮に null を返すだけにしておく } }
この中で、ポイントとなるのは Execute メソッドだ。
この Execute メソッドには、式木が渡ってくる。この式木を解釈してやって、そこからコレクションとしての結果を返してやれば良い。
ここは後で実装することにして、とりあえずは null を返すだけにしておく。
ExpressionVisitor の派生クラスで Visitor パターンによる式木の解釈
LINQ プロバイダーの Execute メソッドでの式木を解釈だが、それには、ExpressionVisitor というクラスが使える。
ExpressionVisitor から派生することで、Visitor パターンによる解析が可能となる。
参考: ExpressionVisitor クラス - MSDN
LINQ のための式木をきちんと解釈するのは、かなり大変なことだ。
ここでは、ごく一部の構文にだけ注目して、そこのみに対応することにする。
取り敢えずの最低限のサンプル コード、Where(text => text.Contains("C#")) の形にのみ対応してみる。
尚、この中では、Twitter のタイムラインを取得する TwitterTimeline クラスを使っているが、 TwitterTimeline クラスは後述する。
// TwitterExpressionVisitor.cs using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; // Visitor パターンで式木を解析して検索用文字列を取り出し、それを使って Twitter のタイムラインを取得する public class TwitterExpressionVisitor : ExpressionVisitor { public IEnumerable<string> Statuses { get; private set; } // 取り敢えずの最低限のサンプル コード // Where(text => text.Contains("C#")) の形にのみ対応してみる protected override Expression VisitMethodCall(MethodCallExpression expression) { // もし Where メソッドを呼ぶ式だったら if (expression.Method.Name == "Where") { // Where メソッドの第二引数であるラムダ式を取り出す var lambdaExpression = (LambdaExpression)((UnaryExpression)(expression.Arguments[1])).Operand; // そのラムダ式の Body 部を取り出す var bodyExpression = lambdaExpression.Body as MethodCallExpression; // もし Contains メソッドを呼ぶ式で if (bodyExpression != null && bodyExpression.Method.Name == "Contains") { // その引数が定数式だったら var constantExpression = bodyExpression.Arguments[0] as ConstantExpression; if (constantExpression != null) { // その定数の値を検索文字列とし var searchText = constantExpression.Value as string; if (searchText != null) // TwitterTimeline クラス (後述) を使って、タイムラインからその検索文字列にあたる Status を取得しておく Statuses = new TwitterTimeline().Filter(searchText).Select(status => status.Text); } } } return base.VisitMethodCall(expression); } }
TwitterTimeline クラスによる Twitter タイムラインの取得
次に、Twitter のタイムラインを取得するためのダミー クラス TwitterTimeline を用意する。
実際に Twitter のタイムラインを取得するコードを用意すれば良いわけだが、今回は説明の簡略化のために CoreTweet というライブラリとダミー コードを用いることにする。
CoreTweet は、Visual Studio から NuGet でインストールできる。
MVP ComCamp -2nd Round- 開催中
『MVP ComCamp -2nd Round- Nov 17 - Nov 21, 2014 が開催されている。
初日に開発者向けセッションを担当 (トラック 2 - Day 1 (2014/11/17): Learn フェイズ)。
発表した資料を公開。
関連記事
「Windows Server 2012 R2 と Windows Server 2003 の混在環境でのコンピューター アカウントのパスワードを変更した後にログオンできない」現象の対処法
【現象】 Windows Server 2003 で構成された Active Directory ドメインに Windows Server 2012 R2 のドメイン コントローラーを追加すると、追加後、2 ヶ月程度経過した後に、ドメインのメンバー、ドメイン コントローラーでログオンができなくなるという現象が発生することがあります。
【解決方法】 Windows Server 2012 R2 をドメイン コントローラーとして追加する前に修正プログラムを適用します。 追加作業をすでに完了している場合には、修正プログラムを Windows Server 2012 R2 のドメイン コントローラーに適用し、ドメイン メンバー (ドメイン コントローラーを含む) 全てを再起動します。 |
具体的な対処方法は下記の通りです。
現象が発生してしまった場合には、対象のコンピューターを再起動します。
再起動することで、起動時に対応した暗号化キーを生成するため、問題が解消します。
問題が発生するのを未然に防ぐためには、次の対応を実施します。
1. KB2989971 を全ての Windows Server 2012 R2 のドメイン コントローラーに適用します。
Windows Server 2012 R2 と Windows Server 2003 の混在環境でのコンピューター アカウントのパスワードを変更した後にログオンできない
http://support.microsoft.com/kb/2989971
2. 全てのドメイン コントローラーに対する修正プログラムの適用処理 (再起動を含む) が完了後に、ドメイン コントローラーを含む全メンバー コンピューターを再起動します。
* KB 2989971 の修正プログラムを適用するためには、下記の 2 点の条件が必要です。
・ KB 2919355 が適用されている事
・ Active Directory ドメインサービスがインストールされている事
※ 役割が追加されていれば、必ずしもドメインコントローラーに昇格している必要はありません。
※ KB2919355 は Windows Update にて配信されているプログラムとなります。
こちらを Windows Update から適用したうえで、以下の修正プログラムを適用ください。
Windows RT 8.1、8.1 の Windows および Windows Server 2012 の R2 の更新プログラム: 2014 年 4 月
http://support.microsoft.com/kb/2919355/ja
【その他】
・ すでに Windows Server 2003 のドメイン コントローラーが降格していてもこの問題は発生する可能性があります。
・ Windows Server 2012 R2 のドメイン コントローラーが存在しており、ログオンができないメンバー上でシステム イベントログにMicrosoft-Windows-Security-Kerberos の ID 4 のイベントが記録されている場合には、この問題に合致している可能性が高いと判断できます。
・ Windows Server 2012 R2 に Active Directory ドメイン サービスをインストールし、ドメイン コントローラーへの昇格を実施する前に修正プログラムを適用することをお勧めします。
そうすれば、この問題の発生を未然に防ぐために全メンバー コンピューターの再起動は不要です。
『ラムダ式でステップアップ! C#のプログラムから汎用的なアルゴリズムを切り出すことで、LINQについての理解を深めよう』 - CodeZine
『Windows 8開発ポケットリファレンス』
本日は、『Windows 8開発ポケットリファレンス』についてのご紹介です。
タイトル | 『Windows 8 開発ポケットリファレンス』 |
著者 | WINGSプロジェクト 阿佐志保,森島政人,飯島聡,土井毅,花田善仁 著,山田祥寛 監修 |
定価 | 定価(本体2,880円+税) |
発売日 | 2014年2月19日発売 |
サイズ | 四六判/496ページ |
ISBN | 978-4-7741-6296-6 |
Webサイト |
特長
- 本書では、Windows 8 以降で動作するストアアプリを作成するとき、作りたい機能から逆引きで作り方を学べます。
- Windows 8.1 に対応しています。8.1 だけで 8 に対応していないものはそれが明記されています。
- ストアアプリならではの、デスクトップアプリケーションとは異なる作り方を、きちんと説明しています。
- 必要な部分だけのシンプルなソースコードです。
- XAML に慣れていない人にも分かりやすく書かれています。
- 新しい API である WinRT についての豊富なサンプル
逆引きとして便利に使えるだけではありません。
本書は順に、
- 開発環境の準備の仕方
- 画面の作り方と様々なコントロールを使うサンプル
- 応用的な画面の作り方
- ストレージや様々なデバイスの使い方
- アプリの連携の方法
- その他の便利な機能
- 非同期プログラミングのやり方
という構成になっています。後ろに行くほど応用的な内容となっているため、順に読み進め、サンプルを打ち込んでいくと、自然に Windows 8 アプリが作れるようになっています。
新しい技術を習得するには、先ず慣れることです。そのためには、動作するサンプルを実際に書いて動かしてみることが効果的です。次には、様々な機能を入れた作りたいアプリケーションを作ってみること。
そのどちらにも有効です。
ストアアプリ開発の初学者から使える良書です。他に同様の書籍は見当たりません。お勧めです。