using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace TestProvider { /// /// http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx /// から取ってきたソース。 /// これくらい、標準で提供してくれてもいいのに。 /// public class Query : IQueryable, IQueryable, IEnumerable, IEnumerable, IOrderedQueryable, IOrderedQueryable { QueryProvider provider; Expression expression; public Query(QueryProvider provider) { if (provider == null) { throw new ArgumentNullException("provider"); } this.provider = provider; this.expression = Expression.Constant(this); } public Query(QueryProvider provider, Expression expression) { if (provider == null) { throw new ArgumentNullException("provider"); } if (expression == null) { throw new ArgumentNullException("expression"); } if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) { throw new ArgumentOutOfRangeException("expression"); } this.provider = provider; this.expression = expression; } Expression IQueryable.Expression { get { return this.expression; } } Type IQueryable.ElementType { get { return typeof(T); } } IQueryProvider IQueryable.Provider { get { return this.provider; } } public IEnumerator GetEnumerator() { return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator(); } public override string ToString() { return this.provider.GetQueryText(this.expression); } } public abstract class QueryProvider : IQueryProvider { protected QueryProvider() { } IQueryable IQueryProvider.CreateQuery(Expression expression) { return new Query(this, expression); } IQueryable IQueryProvider.CreateQuery(Expression expression) { Type elementType = TypeSystem.GetElementType(expression.Type); try { return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression }); } catch (TargetInvocationException tie) { throw tie.InnerException; } } S IQueryProvider.Execute(Expression expression) { return (S)this.Execute(expression); } object IQueryProvider.Execute(Expression expression) { return this.Execute(expression); } public abstract string GetQueryText(Expression expression); public abstract object Execute(Expression expression); } internal static class TypeSystem { internal static Type GetElementType(Type seqType) { Type ienum = FindIEnumerable(seqType); if (ienum == null) return seqType; return ienum.GetGenericArguments()[0]; } private static Type FindIEnumerable(Type seqType) { if (seqType == null || seqType == typeof(string)) return null; if (seqType.IsArray) return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); if (seqType.IsGenericType) { foreach (Type arg in seqType.GetGenericArguments()) { Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); if (ienum.IsAssignableFrom(seqType)) { return ienum; } } } Type[] ifaces = seqType.GetInterfaces(); if (ifaces != null && ifaces.Length > 0) { foreach (Type iface in ifaces) { Type ienum = FindIEnumerable(iface); if (ienum != null) return ienum; } } if (seqType.BaseType != null && seqType.BaseType != typeof(object)) { return FindIEnumerable(seqType.BaseType); } return null; } } }