LordTerabyte

Custom Linq Extension Methods

May 23rd, 2012
1,967
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. class ExpandableMethodAttribute :
  2.         Attribute
  3. {
  4.     public ExpandableMethodAttribute()
  5.     {
  6.     }
  7. }
  8.  
  9. static class Extensions
  10. {
  11.     // Example extension method
  12.     //[ExpandableMethod]
  13.     //public static IQueryable<YOUR_ENTITY> ExampleMethod(this IQueryable<YOUR_ENTITY> source, other args... )
  14.     //{
  15.     //  return source.Where( ... ) or something similar;
  16.     //}
  17.  
  18.     public static IQueryable<T> AsExtendable<T>(this IQueryable<T> source)
  19.     {
  20.         if (source is ExtendableQuery<T>)
  21.         {
  22.             return (ExtendableQuery<T>)source;
  23.         }
  24.  
  25.         return new ExtendableQueryProvider(source.Provider).CreateQuery<T>(source.Expression);
  26.     }
  27. }
  28.  
  29. class ExtendableVisitor : System.Linq.Expressions.ExpressionVisitor
  30. {
  31.     IQueryProvider _provider;
  32.  
  33.     internal ExtendableVisitor(IQueryProvider provider)
  34.     {
  35.         _provider = provider;
  36.     }
  37.  
  38.     protected override Expression VisitMethodCall(MethodCallExpression node)
  39.     {
  40.         bool expandNode = node.Method.GetCustomAttributes(typeof(ExpandableMethodAttribute), false).Any();
  41.         if (expandNode && node.Method.IsStatic)
  42.         {
  43.             object[] args = new object[node.Arguments.Count];
  44.             args[0] = _provider.CreateQuery(node.Arguments[0]);
  45.  
  46.             for (int i = 1; i < node.Arguments.Count; i++)
  47.             {
  48.                 Expression arg = node.Arguments[i];
  49.                 args[i] = (arg.NodeType == ExpressionType.Constant) ? ((ConstantExpression)arg).Value : arg;
  50.             }
  51.  
  52.             Expression exp = ((IQueryable)node.Method.Invoke(null, args)).Expression;
  53.  
  54.             return exp;
  55.         }            
  56.  
  57.         return base.VisitMethodCall(node);
  58.     }
  59. }
  60.  
  61. class ExtendableQuery<T> : IQueryable<T>, IOrderedQueryable<T>
  62. {
  63.     ExtendableQueryProvider _provider;
  64.     Expression _expression;
  65.  
  66.     public ExtendableQuery(ExtendableQueryProvider provider, Expression expression)
  67.     {
  68.         _provider = provider;
  69.         _expression = expression;
  70.     }
  71.  
  72.     public IEnumerator<T> GetEnumerator()
  73.     {
  74.         return _provider.ExecuteQuery<T>(_expression).GetEnumerator();
  75.     }
  76.  
  77.     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  78.     {
  79.         return GetEnumerator();
  80.     }
  81.  
  82.     public Type ElementType
  83.     {
  84.         get {
  85.             return typeof(T);
  86.         }
  87.     }
  88.  
  89.     public Expression Expression
  90.     {
  91.         get {
  92.             return _expression;    
  93.         }
  94.     }
  95.  
  96.     public IQueryProvider Provider
  97.     {
  98.         get {
  99.             return _provider;
  100.         }
  101.     }
  102.  
  103.    
  104. }
  105.  
  106. class ExtendableQueryProvider : IQueryProvider
  107. {
  108.     IQueryProvider _underlyingQueryProvider;
  109.  
  110.     private ExtendableQueryProvider()
  111.     {
  112.     }
  113.  
  114.     internal ExtendableQueryProvider(IQueryProvider underlyingQueryProvider)
  115.     {
  116.         _underlyingQueryProvider = underlyingQueryProvider;
  117.     }
  118.  
  119.     public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
  120.     {
  121.         return new ExtendableQuery<TElement>(this, expression);
  122.     }
  123.  
  124.     public IQueryable CreateQuery(Expression expression)
  125.     {
  126.         Type elementType = expression.Type.GetElementType();
  127.         try
  128.         {
  129.             return (IQueryable)Activator.CreateInstance(typeof(ExtendableQuery<>).MakeGenericType(elementType), new object[] { this, expression });
  130.         }
  131.         catch (System.Reflection.TargetInvocationException tie)
  132.         {
  133.             throw tie.InnerException;
  134.         }
  135.     }
  136.  
  137.     internal IEnumerable<T> ExecuteQuery<T>(Expression expression)
  138.     {
  139.         return _underlyingQueryProvider.CreateQuery<T>(Visit(expression)).AsEnumerable();
  140.     }
  141.  
  142.     public TResult Execute<TResult>(Expression expression)
  143.     {
  144.         return _underlyingQueryProvider.Execute<TResult>(Visit(expression));
  145.     }
  146.  
  147.     public object Execute(Expression expression)
  148.     {
  149.         return _underlyingQueryProvider.Execute(Visit(expression));
  150.     }
  151.  
  152.     private Expression Visit(Expression exp)
  153.     {
  154.         ExtendableVisitor vstr = new ExtendableVisitor(_underlyingQueryProvider);
  155.         Expression visitedExp = vstr.Visit(exp);
  156.  
  157.         return visitedExp;
  158.     }
  159. }
  160.  
  161. // Usage
  162. // YOUR_OBJECT_SET.AsExtendable().ExampleMethod( ... );
RAW Paste Data