SHARE
TWEET

Custom Linq Extension Methods

LordTerabyte May 23rd, 2012 1,267 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
Want to get better at C#?
Learn to code C# in 2017
Top