LordTerabyte

Custom Linq Extension Methods

May 23rd, 2012
2,092
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×