Click here to Skip to main content
15,891,375 members
Articles / Database Development / SQL Server

CLinq - LINQ support for the C++/CLI language

Rate me:
Please Sign up or sign in to vote.
4.86/5 (22 votes)
27 Jul 2007Ms-PL19 min read 64.2K   1.1K   37  
CLinq project is a library that makes it possible to use LINQ technologies from the C++/CLI language
#pragma once

// Ugly macros that make it a bit simpler to write Expr<IEnumerable<T>> (see below)
#define DEC_METHOD_CACHE1(name, sname, a0) \
	static MethodInfo^ _ ## name; static MethodInfo^ Method_ ## name (... cli::array<Type^>^ gt) { \
		if (_ ## name == nullptr) _ ## name = GetGenericMethod(Seq, sname, gcnew array<Type^>{ a0 })->MakeGenericMethod(gt); return _ ## name; }
#define DEC_METHOD_CACHE2(name, sname, a0, a1) \
	static MethodInfo^ _ ## name; static MethodInfo^ Method_ ## name (... cli::array<Type^>^ gt) { \
		if (_ ## name == nullptr) _ ## name = GetGenericMethod(Seq, sname, gcnew array<Type^>{ a0, a1 })->MakeGenericMethod(gt); return _ ## name; }
#define DEC_METHOD_CACHE3(name, sname, a0, a1, a2) \
	static MethodInfo^ _ ## name; static MethodInfo^ Method_ ## name (... cli::array<Type^>^ gt) { \
		if (_ ## name == nullptr) _ ## name = GetGenericMethod(Seq, sname, gcnew array<Type^>{ a0, a1, a2 })->MakeGenericMethod(gt); return _ ## name; }
#define DEC_METHOD_CACHE5(name, sname, a0, a1, a2, a3, a4) \
	static MethodInfo^ _ ## name; static MethodInfo^ Method_ ## name (... cli::array<Type^>^ gt) { \
		if (_ ## name == nullptr) _ ## name = GetGenericMethod(Seq, sname, gcnew array<Type^>{ a0, a1, a2, a3, a4 })->MakeGenericMethod(gt); return _ ## name; }

#include "clinqcore.h"
#include "clinqtyped.h"

using namespace System;
using namespace System::Query;
using namespace System::Reflection;
using namespace System::Collections::Generic;

namespace EeekSoft {
	namespace CLinq {

		/// <summary>
		/// Searches for method by it's name and types. Finds generic methods as well.
		/// (Expects that parameters will be types without generic parameters)
		/// </summary>
		MethodInfo^ GetGenericMethod(Type^ type, String^ name, ... cli::array<Type^>^ args)
		{
			for each(MethodInfo^ mi in type->GetMethods())
			{
				if (mi->Name != name) continue;
				cli::array<ParameterInfo^>^ pi = mi->GetParameters();
				if (pi->Length != args->Length) continue;

				for(int i=0; i<args->Length; i++)
					if (pi[i]->ParameterType->GetGenericTypeDefinition() != args[i]) goto failed;
				return mi;
			failed:;
			}
			return nullptr;
		}


		/// <summary>
		/// This generic class represents pair of values.
		/// </summary>
		generic<typename A, typename B> ref class Tuple
		{
		private:
			A _a;
			B _b;

		public:
			/// <summary>
			/// Initializes the values stored in the class.
			/// </summary>
			Tuple([PropMap("First")] A first, [PropMap("Second")] B second) 
			{
				_a = first; _b = second;
			}

			/// <summary>
			/// TODO: May CTP bug workaround (can't use MemberInit and call Ctor in one expression)
			/// </summary>
			Tuple() { }

			/// <summary>
			/// Gets or sets the first value stored in the tuple.
			/// </summary>
			property A First { 
				A get() { return _a; } 
				void set(A value) { _a = value; }
			}

			/// <summary>
			/// Gets or sets the second value stored in the tuple.
			/// </summary>
			property B Second { 
				B get() { return _b; } 
				void set(B value) { _b = value; }
			}
		};


		/// <summary>
		/// Expr template specialization for working with the Tuple type
		/// </summary>
		template<class A, class B> ref class Expr<Tuple<A, B>^> : ExpressionWrapper<Tuple<A, B>^>
		{
		public:
			static property Type^ WrappedType { Type^ get() { return Tuple<A, B>::typeid; } }
    
		public:
			Expr<Tuple<A, B>^>() { }
			Expr<Tuple<A, B>^>(Tuple<A, B>^ val) { _value = gcnew Literal<Tuple<A, B>^>(val); }
			Expr<Tuple<A, B>^>(Expression<Tuple<A, B>^>^ value) { _value = value; }
			Expr<Tuple<A, B>^>(Expr<Tuple<A, B>^>% b)	{ _value = b._value; }
			operator Expression<Tuple<A, B>^>^() { return _value; }
			operator GenericExpression^() { return _value; }
			static operator Expr<Tuple<A, B>^>(Expression<Tuple<A, B>^>^ value)  { return Expr<Tuple<A, B>^>(value); }
			static operator Expr<Tuple<A, B>^>(Tuple<A, B>^ b) { return Expr<Tuple<A, B>^>(b); }

		public:
			static Expr<Tuple<A, B>^> Typed(GenericExpression^ value) 
			{ 
				return Expr<Tuple<A, B>^>(gcnew TypedExpression<Tuple<A, B>^>(value));
			}

			static Expr<Tuple<A, B>^> Convert(GenericExpression^ value) 
			{ 
				return Expr<Tuple<A, B>^>(gcnew ConvertExpression<Tuple<A, B>^>(value));
			}

		private:
			static property Type^ Tup 
			{
				Type^ get() { return Tuple<A, B>::typeid; }
			}

		public:
			/// <summary>
			/// Represents getting the first value stored in tuple
			/// </summary>
			property Expr<A> First
			{
				Expr<A> get()
				{
					return Expr<A>(gcnew PropertyExpression<A>(Tup->GetProperty("First"), this));
				}
			}

			/// <summary>
			/// Represents getting the second value stored in tuple
			/// </summary>
			property Expr<B> Second
			{
				Expr<B> get()
				{
					return Expr<B>(gcnew PropertyExpression<B>(Tup->GetProperty("Second"), this)); 
				}
			}
		};


		/// <summary>
		/// Expr template specialization for working with the IEnumerable type
		/// </summary>
		template<class T> ref class Expr<IEnumerable<T>^> : ExpressionWrapper<IEnumerable<T>^>
		{
		public:
			static property Type^ WrappedType { Type^ get() { return IEnumerable<T>::typeid; } }
    
		public:
			Expr<IEnumerable<T>^>() { }
			Expr<IEnumerable<T>^>(IEnumerable<T>^ val) { _value = gcnew Literal<IEnumerable<T>^>(val); }
			Expr<IEnumerable<T>^>(Expression<IEnumerable<T>^>^ value) { _value = value; }
			Expr<IEnumerable<T>^>(Expr<IEnumerable<T>^>% b)	{ _value = b._value; }
			operator Expression<IEnumerable<T>^>^() { return _value; }
			operator GenericExpression^() { return _value; }
			static operator Expr<IEnumerable<T>^>(Expression<IEnumerable<T>^>^ value)  { return Expr<IEnumerable<T>^>(value); }
			static operator Expr<IEnumerable<T>^>(IEnumerable<T>^ b) { return Expr<IEnumerable<T>^>(b); }

		public:
			static Expr<IEnumerable<T>^> Typed(GenericExpression^ value) 
			{ 
				return Expr<IEnumerable<T>^>(gcnew TypedExpression<IEnumerable<T>^>(value));
			}

			static Expr<IEnumerable<T>^> Convert(GenericExpression^ value) 
			{ 
				return Expr<IEnumerable<T>^>(gcnew ConvertExpression<IEnumerable<T>^>(value));
			}

		private:
			static cli::array<Type^>^ _funcTypes;

			static property Type^ Seq 
			{
				Type^ get() { return System::Query::Sequence::typeid; }
			}

			static property cli::array<Type^>^ FuncTypes
			{
				cli::array<Type^>^ get() 
				{
					if (_funcTypes == nullptr)
						_funcTypes = gcnew cli::array<Type^> 
						{
							nullptr,
							System::Query::Func::typeid,
							(System::Query::Func<int,int>::typeid)->GetGenericTypeDefinition(),
							(System::Query::Func<int,int,int>::typeid)->GetGenericTypeDefinition(),
							(System::Query::Func<int,int,int,int>::typeid)->GetGenericTypeDefinition(),
						};
					return _funcTypes;
				}
			}

		private:
			// Ugly macros that declare reflection cache...
			DEC_METHOD_CACHE1(Count, "Count", IEnumerable::typeid);
			DEC_METHOD_CACHE2(Count2, "Count", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(Select, "Select", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(Where, "Where", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(SelectMany, "SelectMany", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE5(Join, "Join", IEnumerable::typeid, IQueryable::typeid, FuncTypes[2], FuncTypes[2], FuncTypes[2] );
			DEC_METHOD_CACHE5(GroupJoin, "GroupJoin", IEnumerable::typeid, IQueryable::typeid, FuncTypes[2], FuncTypes[2], FuncTypes[2] );
			DEC_METHOD_CACHE2(OrderBy, "OrderBy", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(OrderByDescending, "OrderByDescending", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE1(First, "First", IEnumerable::typeid );
			DEC_METHOD_CACHE1(FirstOrDefault, "FirstOrDefault", IEnumerable::typeid );
			DEC_METHOD_CACHE1(Last, "Last", IEnumerable::typeid );
			DEC_METHOD_CACHE1(LastOrDefault, "LastOrDefault", IEnumerable::typeid );
			DEC_METHOD_CACHE1(Single, "Single", IEnumerable::typeid );
			DEC_METHOD_CACHE1(SingleOrDefault, "SingleOrDefault", IEnumerable::typeid );
			DEC_METHOD_CACHE1(Any, "Any", IEnumerable::typeid );
			DEC_METHOD_CACHE1(Min, "Min", IEnumerable::typeid );
			DEC_METHOD_CACHE1(Max, "Max", IEnumerable::typeid );
			DEC_METHOD_CACHE1(LongCount, "LongCount", IEnumerable::typeid );
			DEC_METHOD_CACHE2(LongCount2, "LongCount", IEnumerable::typeid, FuncTypes[2] );			
			DEC_METHOD_CACHE2(Sum, "Sum", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(Average, "Average", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(GroupBy, "GroupBy", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE3(GroupBy2, "GroupBy2", IEnumerable::typeid, FuncTypes[2], FuncTypes[2] );
			DEC_METHOD_CACHE2(Concat, "Concat", IEnumerable::typeid, IQueryable::typeid );
			DEC_METHOD_CACHE2(Union, "Union", IEnumerable::typeid, IQueryable::typeid );
			DEC_METHOD_CACHE2(Intersect, "Intersect", IEnumerable::typeid, IQueryable::typeid );
			DEC_METHOD_CACHE2(Except, "Except", IEnumerable::typeid, IQueryable::typeid );
			DEC_METHOD_CACHE2(All, "All", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(Any2, "Any2", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(Last2, "Last2", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(Single2, "Single2", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(First2, "First2", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(LastOrDefault2, "LastOrDefault2", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(SingleOrDefault2, "SingleOrDefault2", IEnumerable::typeid, FuncTypes[2] );
			DEC_METHOD_CACHE2(FirstOrDefault2, "FirstOrDefault2", IEnumerable::typeid, FuncTypes[2] );

		public:

			/// <summary>
			/// The Select operator performs a projection over a sequence
			/// </summary>
			template<class R> Expr<IEnumerable<R>^> Select(Lambda<System::Query::Func<T, R>^>^ selector)
			{
				return Expr<IEnumerable<R>^>(gcnew MethodInvokeExpression<IEnumerable<R>^>
					(Method_Select(T::typeid, R::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Where operator filters a sequence based on a predicate
			/// </summary>
			Expr<IEnumerable<T>^> Where(Lambda<System::Query::Func<T, bool>^>^ filter)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Where(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The SelectMany operator performs a one to many element projection over a sequence.
			/// </summary>
			template<class S> Expr<IEnumerable<S>^> SelectMany(Lambda<Func<T, IEnumerable<S>^>^>^ selector)
			{
				return Expr<IEnumerable<S>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_SelectMany(T::typeid, S::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Join operator performs an inner join of two sequences based on matching keys extracted from the elements.
			/// </summary>
			template<class U, class K, class V> Expr<IEnumerable<V>^> Join(Expr<IQueryable<U>^> inner, Lambda<Func<T,K>^>^ outerKeySelector, 
				Lambda<Func<U,K>^>^ innerKeySelector, Lambda<Func<T,U,V>^>^ resultSelector)
			{
				return Expr<IEnumerable<S>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Join(T::typeid, K::typeid, V::typeid), this, gcnew array<GenericExpression^>{ this, inner, outerKeySelector, innerKeySelector, resultSelector } ));
			}

			/// <summary>
			/// The GroupJoin operator performs a grouped join of two sequences based on matching keys extracted from the elements.
			/// </summary>
			template<class U, class K, class V> Expr<IEnumerable<V>^> GroupJoin(Expr<IQueryable<U>^> inner, Lambda<Func<T,K>^>^ outerKeySelector, 
				Lambda<Func<U,K>^>^ innerKeySelector, Lambda<Func<T,IEnumerable<U>^,V>^>^ resultSelector)
			{
				return Expr<IEnumerable<V>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_GroupJoin(T::typeid, U::typeid, K::typeid, V::typeid), this, gcnew array<GenericExpression^>{ this, inner, outerKeySelector, innerKeySelector, resultSelector } ));
			}

			/// <summary>
			/// The OrderBy operator orders a sequence according to one or more keys in ascending order.
			/// </summary>
			template<class K> Expr<IEnumerable<T>^> OrderBy(Lambda<Func<T,K>^>^ keySelector)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_OrderBy(T::typeid, K::typeid), this, gcnew array<GenericExpression^>{ this, keySelector } ));
			}

			/// <summary>
			/// he OrderBy operator orders a sequence according to one or more keys in descending order.
			/// </summary>
			template<class K> Expr<IEnumerable<T>^> OrderByDescending(Lambda<Func<T, K>^>^ keySelector)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_OrderByDescending(T::typeid, K::typeid), this, gcnew array<GenericExpression^>{ this, keySelector } ));
			}

			/// <summary>
			/// The First operator returns the first element of a sequence.
			/// </summary>
			Expr<T> First()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_First(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The FirstOrDefault operator returns the first element of a sequence, or a default value if no element is found.
			/// </summary>
			Expr<T> FirstOrDefault()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_FirstOrDefault(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Last operator returns the last element of a sequence.
			/// </summary>
			Expr<T> Last()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_Last(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The LastOrDefault operator returns the last element of a sequence, or a default value if no element is found.
			/// </summary>
			Expr<T> LastOrDefault()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_LastOrDefault(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Single operator returns the single element of a sequence.
			/// </summary>
			Expr<T> Single()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_Single(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The SingleOrDefault operator returns the single element of a sequence, or a default value if no element is found.
			/// </summary>
			Expr<T> SingleOrDefault()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_SingleOrDefault(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Any operator checks whether any element of a sequence satisfies a condition.
			/// </summary>
			Expr<bool> Any()
			{
				return Expr<bool>(gcnew MethodInvokeExpression<bool>
					(Method_Any(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Min operator finds the minimum of a sequence of numeric values.
			/// </summary>
			Expr<T> Min()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_Min(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Max operator finds the maximum of a sequence of numeric values.
			/// </summary>
			Expr<T> Max()
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_Max(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The LongCount operator counts the number of elements in a sequence with a return type of Long.
			/// </summary>
			Expr<long long int> LongCount()
			{
				return Expr<long long int>(gcnew MethodInvokeExpression<long long int>
					(Method_LongCount(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Count operator counts the number of elements in a sequence with a return type of int.
			/// </summary>
			Expr<int> Count()
			{
				return Expr<int>(gcnew MethodInvokeExpression<int>
					(Method_Count(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Count operator counts the number of elements in a sequence with a return type of int.
			/// </summary>
			Expr<int> Count(Lambda<System::Query::Func<T, bool>^>^ filter)
			{
				return Expr<int>(gcnew MethodInvokeExpression<int>
					(Method_Count2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The GroupBy operator groups the elements of a sequence.
			/// </summary>
			template<class K> Expr<IEnumerable<IGrouping<K, T>^>^> GroupBy(Lambda<Func<T, K>^>^ keySelector)
			{
				return Expr<IEnumerable<IGrouping<K, T>^>^>(gcnew MethodInvokeExpression<IEnumerable<IGrouping<K, T>^>^>
					(Method_GroupBy(T::typeid, K::typeid), this, gcnew array<GenericExpression^>{ this, keySelector } ));
			}

			/// <summary>
			/// The GroupBy operator groups the elements of a sequence.
			/// </summary>
			template<class K, class E> Expr<IEnumerable<IGrouping<K, E>^>^> GroupBy(Lambda<Func<T, K>^>^ keySelector, Lambda<Func<T, E>^>^ elementSelector)
			{
				return Expr<IEnumerable<IGrouping<K, E>^>^>(gcnew MethodInvokeExpression<IEnumerable<IGrouping<K, E>^>^>
					(Method_GroupBy2(T::typeid, K::typeid, E::typeid), this, gcnew array<GenericExpression^>{ this, keySelector, elementSelector } ));
			}
			
			/// <summary>
			/// The Min operator finds the minimum of a sequence of numeric values.
			/// </summary>
			template<class V> Expr<V> Min(Lambda<Func<T, V>^>^ selector)
			{
				return Expr<V>(gcnew MethodInvokeExpression<V>
					(Method_Min(T::typeid, V::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Max operator finds the maximum of a sequence of numeric values. 
			/// </summary>
			template<class V> Expr<V> Max(Lambda<Func<T, V>^>^ selector)
			{
				return Expr<V>(gcnew MethodInvokeExpression<V>
					(Method_Max(T::typeid, V::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Take operator yields a given number of elements from a sequence and then skips the remainder of the sequence.
			/// </summary>
			Expr<IEnumerable<T>^> Take(Expr<int> count)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Take(T::typeid), this, gcnew array<GenericExpression^>{ this, count } ));
			}

			/// <summary>
			/// The Skip operator skips a given number of elements from a sequence and then yields the remainder of the sequence.
			/// </summary>
			Expr<IEnumerable<T>^> Skip(Expr<int> count)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Skip(T::typeid), this, gcnew array<GenericExpression^>{ this, count } ));
			}

			/// <summary>
			/// The Distinct operator eliminates duplicate elements from a sequence.
			/// </summary>
			Expr<IEnumerable<T>^> Distinct()
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Distinct(T::typeid), this, gcnew array<GenericExpression^>{ this } ));
			}

			/// <summary>
			/// The Concat operator concatenates two sequences.
			/// </summary>
			Expr<IEnumerable<T>^> Concat(Expr<IQueryable<T>^> source)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Concat(T::typeid), this, gcnew array<GenericExpression^>{ this, source } ));
			}

			/// <summary>
			/// The Union operator produces the set union of two sequences.
			/// </summary>
			Expr<IEnumerable<T>^> Union(Expr<IQueryable<T>^> source)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Union(T::typeid), this, gcnew array<GenericExpression^>{ this, source } ));
			}

			/// <summary>
			/// The Intersect operator produces the set intersection of two sequences.
			/// </summary>
			Expr<IEnumerable<T>^> Intersect(Expr<IQueryable<T>^> source)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Intersect(T::typeid), this, gcnew array<GenericExpression^>{ this, source } ));
			}

			/// <summary>
			/// The Except operator produces the set difference between two sequences.
			/// </summary>
			Expr<IEnumerable<T>^> Except(Expr<IQueryable<T>^> source)
			{
				return Expr<IEnumerable<T>^>(gcnew MethodInvokeExpression<IEnumerable<T>^>
					(Method_Except(T::typeid), this, gcnew array<GenericExpression^>{ this, source } ));
			}

			/// <summary>
			/// The First operator returns the first element of a sequence.
			/// </summary>
			Expr<T> First(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_First2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The FirstOrDefault operator returns the first element of a sequence, or a default value if no element is found.
			/// </summary>
			Expr<T> FirstOrDefault(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_FirstOrDefault2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The Last operator returns the last element of a sequence.
			/// </summary>
			Expr<T> Last(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_Last2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The LastOrDefault operator returns the last element of a sequence, or a default value if no element is found.
			/// </summary>
			Expr<T> LastOrDefault(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_LastOrDefault2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The Single operator returns the single element of a sequence.
			/// </summary>
			Expr<T> Single(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_Single2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The SingleOrDefault operator returns the single element of a sequence, or a default value if no element is found.
			/// </summary>
			Expr<T> SingleOrDefault(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<T>(gcnew MethodInvokeExpression<T>
					(Method_SingleOrDefault2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The Any operator checks whether any element of a sequence satisfies a condition.
			/// </summary>
			Expr<bool> Any(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<bool>(gcnew MethodInvokeExpression<bool>
					(Method_Any2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The All operator checks whether all elements of a sequence satisfy a condition.
			/// </summary>
			Expr<bool> All(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<bool>(gcnew MethodInvokeExpression<bool>
					(Method_All2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The LongCount operator counts the number of elements in a sequence with a return type of Long.
			/// </summary>
			Expr<long long int> LongCount(Lambda<Func<T, bool>^>^ filter)
			{
				return Expr<long long int>(gcnew MethodInvokeExpression<long long int>
					(Method_LongCount2(T::typeid), this, gcnew array<GenericExpression^>{ this, filter } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<int> Sum(Lambda<System::Query::Func<T, int>^>^ selector)
			{
				return Expr<int>(gcnew MethodInvokeExpression<int>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<double> Average(Lambda<System::Query::Func<T, int>^>^ selector)
			{
				return Expr<double>(gcnew MethodInvokeExpression<double>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<long long int> Sum(Lambda<System::Query::Func<T, long long int>^>^ selector)
			{
				return Expr<long long int>(gcnew MethodInvokeExpression<long long int>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<double> Average(Lambda<System::Query::Func<T, long long int>^>^ selector)
			{
				return Expr<double>(gcnew MethodInvokeExpression<double>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<double> Sum(Lambda<System::Query::Func<T, double>^>^ selector)
			{
				return Expr<double>(gcnew MethodInvokeExpression<double>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<double> Average(Lambda<System::Query::Func<T, double>^>^ selector)
			{
				return Expr<double>(gcnew MethodInvokeExpression<double>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<Decimal> Sum(Lambda<System::Query::Func<T, Decimal>^>^ selector)
			{
				return Expr<Decimal>(gcnew MethodInvokeExpression<Decimal>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<Decimal> Average(Lambda<System::Query::Func<T, Decimal>^>^ selector)
			{
				return Expr<Decimal>(gcnew MethodInvokeExpression<Decimal>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<int>> Sum(Lambda<System::Query::Func<T, Nullable<int>>^>^ selector)
			{
				return Expr<Nullable<int>>(gcnew MethodInvokeExpression<Nullable<int>>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<double>> Average(Lambda<System::Query::Func<T, Nullable<int>>^>^ selector)
			{
				return Expr<Nullable<double>>(gcnew MethodInvokeExpression<Nullable<double>>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<long long int>> Sum(Lambda<System::Query::Func<T, Nullable<long long int>>^>^ selector)
			{
				return Expr<Nullable<long long int>>(gcnew MethodInvokeExpression<Nullable<long long int>>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<double>> Average(Lambda<System::Query::Func<T, Nullable<long long int>>^>^ selector)
			{
				return Expr<Nullable<double>>(gcnew MethodInvokeExpression<Nullable<double>>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<double>> Sum(Lambda<System::Query::Func<T, Nullable<double>>^>^ selector)
			{
				return Expr<Nullable<double>>(gcnew MethodInvokeExpression<Nullable<double>>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<double>> Average(Lambda<System::Query::Func<T, Nullable<double>>^>^ selector)
			{
				return Expr<Nullable<double>>(gcnew MethodInvokeExpression<Nullable<double>>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Sum operator computes the sum of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<Decimal>> Sum(Lambda<System::Query::Func<T, Nullable<Decimal>>^>^ selector)
			{
				return Expr<Nullable<Decimal>>(gcnew MethodInvokeExpression<Nullable<Decimal>>
					(Method_Sum(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}

			/// <summary>
			/// The Average operator computes the average of a sequence of numeric values.
			/// </summary>
			Expr<Nullable<Decimal>> Average(Lambda<System::Query::Func<T, Nullable<Decimal>>^>^ selector)
			{
				return Expr<Nullable<Decimal>>(gcnew MethodInvokeExpression<Nullable<Decimal>>
					(Method_Average(T::typeid), this, gcnew array<GenericExpression^>{ this, selector } ));
			}
		};


		/// <summary>
		/// Expr template specialization for working with the IGrouping type
		/// </summary>
		template<class T, class K> ref class Expr<IGrouping<K, T>^> : ExpressionWrapper<IGrouping<K, T>^>
		{
		public:
			static property Type^ WrappedType { Type^ get() { return IGrouping<K, T>::typeid; } }
    
		public:
			Expr<IGrouping<K, T>^>() { }
			Expr<IGrouping<K, T>^>(IGrouping<K, T>^ val) { _value = gcnew Literal<IGrouping<K, T>^>(val); }
			Expr<IGrouping<K, T>^>(Expression<IGrouping<K, T>^>^ value) { _value = value; }
			Expr<IGrouping<K, T>^>(Expr<IGrouping<K, T>^>% b)	{ _value = b._value; }
			operator Expression<IGrouping<K, T>^>^() { return _value; }
			operator GenericExpression^() { return _value; }
			static operator Expr<IGrouping<K, T>^>(Expression<IGrouping<K, T>^>^ value)  { return Expr<IGrouping<K, T>^>(value); }
			static operator Expr<IGrouping<K, T>^>(IGrouping<K, T>^ b) { return Expr<IGrouping<K, T>^>(b); }

		public:
			static Expr<IGrouping<K, T>^> Typed(GenericExpression^ value) 
			{ 
				return Expr<IGrouping<K, T>^>(gcnew TypedExpression<IGrouping<K, T>^>(value));
			}

			static Expr<IGrouping<K, T>^> Convert(GenericExpression^ value) 
			{ 
				return Expr<IGrouping<K, T>^>(gcnew ConvertExpression<IGrouping<K, T>^>(value));
			}

		private:
			static property Type^ Grouping
			{
				Type^ get() { return IGrouping<K, T>::typeid; }
			}

		public:
			/// <summary>
			/// Returns expression representing the Key of the grouping
			/// </summary>
			property Expr<K> Key
			{
				Expr<K> get()
				{
					return Expr<K>(gcnew PropertyExpression<K>(Grouping->GetProperty("Key"), this));
				}
			}

			/// <summary>
			/// Returns expression representing the values of the grouping
			/// </summary>
			property Expr<IEnumerable<T>^> Values
			{
				Expr<IEnumerable<T>^> get()
				{
					return Expr<IEnumerable<T>^>::Typed(this);
				}
			}
		};
} }

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Czech Republic Czech Republic
I live in Prague, the capital city of Czech republic (most of the time Smile | :) ). I've been very interested in functional programming recently and I have a passion for the new Microsoft F# language. I'm writing a book about Functional Programming in the Real World that shows the ideas using examples in C# 3.0 and F#.

I've been Microsoft MVP (for C#) since 2004 and I'm one of the most active members of the F# community. I'm a computer science student at Charles University of Prague. My hobbies include photography, fractals and of course many things related to computers (except fixing them). My favorite book writers are Terry Pratchett and Philip K Dick and I like paintings by M. C. Escher.

PS: My favorite codeproject icon is Sheep | [baah] .

Comments and Discussions