QueryableEx.cs 118 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.ComponentModel;
  6. using System.Globalization;
  7. using System.Linq.Expressions;
  8. using System.Reflection;
  9. namespace System.Linq
  10. {
  11. /// <summary>
  12. /// Provides a set of additional static methods that allow querying enumerable sequences.
  13. /// </summary>
  14. public static class QueryableEx
  15. {
  16. /// <summary>
  17. /// Determines whether an enumerable sequence is empty.
  18. /// </summary>
  19. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  20. /// <param name="source">Source sequence.</param>
  21. /// <returns>true if the sequence is empty; false otherwise.</returns>
  22. public static bool IsEmpty<TSource>(this IQueryable<TSource> source)
  23. {
  24. if (source == null)
  25. {
  26. throw new ArgumentNullException(nameof(source));
  27. }
  28. return source.Provider.Execute<bool>(
  29. Expression.Call(
  30. null,
  31. #if CRIPPLED_REFLECTION
  32. InfoOf(() => QueryableEx.IsEmpty<TSource>(default)),
  33. #else
  34. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  35. #endif
  36. source.Expression
  37. )
  38. );
  39. }
  40. #pragma warning disable 1591
  41. [EditorBrowsable(EditorBrowsableState.Never)]
  42. public static bool IsEmpty<TSource>(IEnumerable<TSource> source)
  43. {
  44. return EnumerableEx.IsEmpty(source);
  45. }
  46. #pragma warning restore 1591
  47. /// <summary>
  48. /// Returns the minimum value in the enumerable sequence by using the specified comparer to compare values.
  49. /// </summary>
  50. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  51. /// <param name="source">Source sequence.</param>
  52. /// <param name="comparer">Comparer used to determine the minimum value.</param>
  53. /// <returns>Minimum value in the sequence.</returns>
  54. public static TSource Min<TSource>(this IQueryable<TSource> source, IComparer<TSource> comparer)
  55. {
  56. if (source == null)
  57. {
  58. throw new ArgumentNullException(nameof(source));
  59. }
  60. if (comparer == null)
  61. {
  62. throw new ArgumentNullException(nameof(comparer));
  63. }
  64. return source.Provider.Execute<TSource>(
  65. Expression.Call(
  66. null,
  67. #if CRIPPLED_REFLECTION
  68. InfoOf(() => QueryableEx.Min<TSource>(default, default)),
  69. #else
  70. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  71. #endif
  72. source.Expression,
  73. Expression.Constant(comparer, typeof(IComparer<TSource>))
  74. )
  75. );
  76. }
  77. #pragma warning disable 1591
  78. [EditorBrowsable(EditorBrowsableState.Never)]
  79. public static TSource Min<TSource>(IEnumerable<TSource> source, IComparer<TSource> comparer)
  80. {
  81. return EnumerableEx.Min(source, comparer);
  82. }
  83. #pragma warning restore 1591
  84. /// <summary>
  85. /// Returns the elements with the minimum key value by using the default comparer to compare key values.
  86. /// </summary>
  87. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  88. /// <typeparam name="TKey">Key type.</typeparam>
  89. /// <param name="source">Source sequence.</param>
  90. /// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
  91. /// <returns>List with the elements that share the same minimum key value.</returns>
  92. public static IList<TSource> MinBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
  93. {
  94. if (source == null)
  95. {
  96. throw new ArgumentNullException(nameof(source));
  97. }
  98. if (keySelector == null)
  99. {
  100. throw new ArgumentNullException(nameof(keySelector));
  101. }
  102. return source.Provider.Execute<IList<TSource>>(
  103. Expression.Call(
  104. null,
  105. #if CRIPPLED_REFLECTION
  106. InfoOf(() => QueryableEx.MinBy<TSource, TKey>(default, default)),
  107. #else
  108. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  109. #endif
  110. source.Expression,
  111. keySelector
  112. )
  113. );
  114. }
  115. #pragma warning disable 1591
  116. [EditorBrowsable(EditorBrowsableState.Never)]
  117. public static IList<TSource> MinBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  118. {
  119. return EnumerableEx.MinBy(source, keySelector);
  120. }
  121. #pragma warning restore 1591
  122. /// <summary>
  123. /// Returns the elements with the minimum key value by using the specified comparer to compare key values.
  124. /// </summary>
  125. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  126. /// <typeparam name="TKey">Key type.</typeparam>
  127. /// <param name="source">Source sequence.</param>
  128. /// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
  129. /// <param name="comparer">Comparer used to determine the minimum key value.</param>
  130. /// <returns>List with the elements that share the same minimum key value.</returns>
  131. public static IList<TSource> MinBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer)
  132. {
  133. if (source == null)
  134. {
  135. throw new ArgumentNullException(nameof(source));
  136. }
  137. if (keySelector == null)
  138. {
  139. throw new ArgumentNullException(nameof(keySelector));
  140. }
  141. if (comparer == null)
  142. {
  143. throw new ArgumentNullException(nameof(comparer));
  144. }
  145. return source.Provider.Execute<IList<TSource>>(
  146. Expression.Call(
  147. null,
  148. #if CRIPPLED_REFLECTION
  149. InfoOf(() => QueryableEx.MinBy<TSource, TKey>(default, default, default)),
  150. #else
  151. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  152. #endif
  153. source.Expression,
  154. keySelector,
  155. Expression.Constant(comparer, typeof(IComparer<TKey>))
  156. )
  157. );
  158. }
  159. #pragma warning disable 1591
  160. [EditorBrowsable(EditorBrowsableState.Never)]
  161. public static IList<TSource> MinBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
  162. {
  163. return EnumerableEx.MinBy(source, keySelector, comparer);
  164. }
  165. #pragma warning restore 1591
  166. /// <summary>
  167. /// Returns the maximum value in the enumerable sequence by using the specified comparer to compare values.
  168. /// </summary>
  169. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  170. /// <param name="source">Source sequence.</param>
  171. /// <param name="comparer">Comparer used to determine the maximum value.</param>
  172. /// <returns>Maximum value in the sequence.</returns>
  173. public static TSource Max<TSource>(this IQueryable<TSource> source, IComparer<TSource> comparer)
  174. {
  175. if (source == null)
  176. {
  177. throw new ArgumentNullException(nameof(source));
  178. }
  179. if (comparer == null)
  180. {
  181. throw new ArgumentNullException(nameof(comparer));
  182. }
  183. return source.Provider.Execute<TSource>(
  184. Expression.Call(
  185. null,
  186. #if CRIPPLED_REFLECTION
  187. InfoOf(() => QueryableEx.Max<TSource>(default, default)),
  188. #else
  189. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  190. #endif
  191. source.Expression,
  192. Expression.Constant(comparer, typeof(IComparer<TSource>))
  193. )
  194. );
  195. }
  196. #pragma warning disable 1591
  197. [EditorBrowsable(EditorBrowsableState.Never)]
  198. public static TSource Max<TSource>(IEnumerable<TSource> source, IComparer<TSource> comparer)
  199. {
  200. return EnumerableEx.Max(source, comparer);
  201. }
  202. #pragma warning restore 1591
  203. /// <summary>
  204. /// Returns the elements with the maximum key value by using the default comparer to compare key values.
  205. /// </summary>
  206. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  207. /// <typeparam name="TKey">Key type.</typeparam>
  208. /// <param name="source">Source sequence.</param>
  209. /// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
  210. /// <returns>List with the elements that share the same maximum key value.</returns>
  211. public static IList<TSource> MaxBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
  212. {
  213. if (source == null)
  214. {
  215. throw new ArgumentNullException(nameof(source));
  216. }
  217. if (keySelector == null)
  218. {
  219. throw new ArgumentNullException(nameof(keySelector));
  220. }
  221. return source.Provider.Execute<IList<TSource>>(
  222. Expression.Call(
  223. null,
  224. #if CRIPPLED_REFLECTION
  225. InfoOf(() => QueryableEx.MaxBy<TSource, TKey>(default, default)),
  226. #else
  227. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  228. #endif
  229. source.Expression,
  230. keySelector
  231. )
  232. );
  233. }
  234. #pragma warning disable 1591
  235. [EditorBrowsable(EditorBrowsableState.Never)]
  236. public static IList<TSource> MaxBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  237. {
  238. return EnumerableEx.MaxBy(source, keySelector);
  239. }
  240. #pragma warning restore 1591
  241. /// <summary>
  242. /// Returns the elements with the minimum key value by using the specified comparer to compare key values.
  243. /// </summary>
  244. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  245. /// <typeparam name="TKey">Key type.</typeparam>
  246. /// <param name="source">Source sequence.</param>
  247. /// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
  248. /// <param name="comparer">Comparer used to determine the maximum key value.</param>
  249. /// <returns>List with the elements that share the same maximum key value.</returns>
  250. public static IList<TSource> MaxBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer)
  251. {
  252. if (source == null)
  253. {
  254. throw new ArgumentNullException(nameof(source));
  255. }
  256. if (keySelector == null)
  257. {
  258. throw new ArgumentNullException(nameof(keySelector));
  259. }
  260. if (comparer == null)
  261. {
  262. throw new ArgumentNullException(nameof(comparer));
  263. }
  264. return source.Provider.Execute<IList<TSource>>(
  265. Expression.Call(
  266. null,
  267. #if CRIPPLED_REFLECTION
  268. InfoOf(() => QueryableEx.MaxBy<TSource, TKey>(default, default, default)),
  269. #else
  270. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  271. #endif
  272. source.Expression,
  273. keySelector,
  274. Expression.Constant(comparer, typeof(IComparer<TKey>))
  275. )
  276. );
  277. }
  278. #pragma warning disable 1591
  279. [EditorBrowsable(EditorBrowsableState.Never)]
  280. public static IList<TSource> MaxBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
  281. {
  282. return EnumerableEx.MaxBy(source, keySelector, comparer);
  283. }
  284. #pragma warning restore 1591
  285. /// <summary>
  286. /// Shares the source sequence within a selector function where each enumerator can fetch the next element from the source sequence.
  287. /// </summary>
  288. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  289. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  290. /// <param name="source">Source sequence.</param>
  291. /// <param name="selector">Selector function with shared access to the source sequence for each enumerator.</param>
  292. /// <returns>Sequence resulting from applying the selector function to the shared view over the source sequence.</returns>
  293. public static IQueryable<TResult> Share<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IEnumerable<TSource>, IEnumerable<TResult>>> selector)
  294. {
  295. if (source == null)
  296. {
  297. throw new ArgumentNullException(nameof(source));
  298. }
  299. if (selector == null)
  300. {
  301. throw new ArgumentNullException(nameof(selector));
  302. }
  303. return source.Provider.CreateQuery<TResult>(
  304. Expression.Call(
  305. null,
  306. #if CRIPPLED_REFLECTION
  307. InfoOf(() => QueryableEx.Share<TSource, TResult>(default, default)),
  308. #else
  309. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
  310. #endif
  311. source.Expression,
  312. selector
  313. )
  314. );
  315. }
  316. #pragma warning disable 1591
  317. [EditorBrowsable(EditorBrowsableState.Never)]
  318. public static IEnumerable<TResult> Share<TSource, TResult>(IEnumerable<TSource> source, Func<IEnumerable<TSource>, IEnumerable<TResult>> selector)
  319. {
  320. return EnumerableEx.Share(source, selector);
  321. }
  322. #pragma warning restore 1591
  323. /// <summary>
  324. /// Publishes the source sequence within a selector function where each enumerator can obtain a view over a tail of the source sequence.
  325. /// </summary>
  326. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  327. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  328. /// <param name="source">Source sequence.</param>
  329. /// <param name="selector">Selector function with published access to the source sequence for each enumerator.</param>
  330. /// <returns>Sequence resulting from applying the selector function to the published view over the source sequence.</returns>
  331. public static IQueryable<TResult> Publish<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IEnumerable<TSource>, IEnumerable<TResult>>> selector)
  332. {
  333. if (source == null)
  334. {
  335. throw new ArgumentNullException(nameof(source));
  336. }
  337. if (selector == null)
  338. {
  339. throw new ArgumentNullException(nameof(selector));
  340. }
  341. return source.Provider.CreateQuery<TResult>(
  342. Expression.Call(
  343. null,
  344. #if CRIPPLED_REFLECTION
  345. InfoOf(() => QueryableEx.Publish<TSource, TResult>(default, default)),
  346. #else
  347. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
  348. #endif
  349. source.Expression,
  350. selector
  351. )
  352. );
  353. }
  354. #pragma warning disable 1591
  355. [EditorBrowsable(EditorBrowsableState.Never)]
  356. public static IEnumerable<TResult> Publish<TSource, TResult>(IEnumerable<TSource> source, Func<IEnumerable<TSource>, IEnumerable<TResult>> selector)
  357. {
  358. return EnumerableEx.Publish(source, selector);
  359. }
  360. #pragma warning restore 1591
  361. /// <summary>
  362. /// Memoizes the source sequence within a selector function where each enumerator can get access to all of the sequence's elements without causing multiple enumerations over the source.
  363. /// </summary>
  364. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  365. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  366. /// <param name="source">Source sequence.</param>
  367. /// <param name="selector">Selector function with memoized access to the source sequence for each enumerator.</param>
  368. /// <returns>Sequence resulting from applying the selector function to the memoized view over the source sequence.</returns>
  369. public static IQueryable<TResult> Memoize<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IEnumerable<TSource>, IEnumerable<TResult>>> selector)
  370. {
  371. if (source == null)
  372. {
  373. throw new ArgumentNullException(nameof(source));
  374. }
  375. if (selector == null)
  376. {
  377. throw new ArgumentNullException(nameof(selector));
  378. }
  379. return source.Provider.CreateQuery<TResult>(
  380. Expression.Call(
  381. null,
  382. #if CRIPPLED_REFLECTION
  383. InfoOf(() => QueryableEx.Memoize<TSource, TResult>(default, default)),
  384. #else
  385. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
  386. #endif
  387. source.Expression,
  388. selector
  389. )
  390. );
  391. }
  392. #pragma warning disable 1591
  393. [EditorBrowsable(EditorBrowsableState.Never)]
  394. public static IEnumerable<TResult> Memoize<TSource, TResult>(IEnumerable<TSource> source, Func<IEnumerable<TSource>, IEnumerable<TResult>> selector)
  395. {
  396. return EnumerableEx.Memoize(source, selector);
  397. }
  398. #pragma warning restore 1591
  399. /// <summary>
  400. /// Memoizes the source sequence within a selector function where a specified number of enumerators can get access to all of the sequence's elements without causing multiple enumerations over the source.
  401. /// </summary>
  402. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  403. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  404. /// <param name="source">Source sequence.</param>
  405. /// <param name="readerCount">Number of enumerators that can access the underlying buffer. Once every enumerator has obtained an element from the buffer, the element is removed from the buffer.</param>
  406. /// <param name="selector">Selector function with memoized access to the source sequence for a specified number of enumerators.</param>
  407. /// <returns>Sequence resulting from applying the selector function to the memoized view over the source sequence.</returns>
  408. public static IQueryable<TResult> Memoize<TSource, TResult>(this IQueryable<TSource> source, int readerCount, Expression<Func<IEnumerable<TSource>, IEnumerable<TResult>>> selector)
  409. {
  410. if (source == null)
  411. {
  412. throw new ArgumentNullException(nameof(source));
  413. }
  414. if (selector == null)
  415. {
  416. throw new ArgumentNullException(nameof(selector));
  417. }
  418. return source.Provider.CreateQuery<TResult>(
  419. Expression.Call(
  420. null,
  421. #if CRIPPLED_REFLECTION
  422. InfoOf(() => QueryableEx.Memoize<TSource, TResult>(default, default, default)),
  423. #else
  424. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
  425. #endif
  426. source.Expression,
  427. Expression.Constant(readerCount, typeof(int)),
  428. selector
  429. )
  430. );
  431. }
  432. #pragma warning disable 1591
  433. [EditorBrowsable(EditorBrowsableState.Never)]
  434. public static IEnumerable<TResult> Memoize<TSource, TResult>(IEnumerable<TSource> source, int readerCount, Func<IEnumerable<TSource>, IEnumerable<TResult>> selector)
  435. {
  436. return EnumerableEx.Memoize(source, readerCount, selector);
  437. }
  438. #pragma warning restore 1591
  439. /// <summary>
  440. /// Creates an enumerable sequence based on an enumerator factory function.
  441. /// </summary>
  442. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  443. /// <param name="provider">Query provider.</param>
  444. /// <param name="getEnumerator">Enumerator factory function.</param>
  445. /// <returns>Sequence that will invoke the enumerator factory upon a call to GetEnumerator.</returns>
  446. public static IQueryable<TResult> Create<TResult>(this IQueryProvider provider, Expression<Func<IEnumerator<TResult>>> getEnumerator)
  447. {
  448. if (provider == null)
  449. {
  450. throw new ArgumentNullException(nameof(provider));
  451. }
  452. if (getEnumerator == null)
  453. {
  454. throw new ArgumentNullException(nameof(getEnumerator));
  455. }
  456. return provider.CreateQuery<TResult>(
  457. Expression.Call(
  458. null,
  459. #if CRIPPLED_REFLECTION
  460. InfoOf(() => QueryableEx.Create<TResult>(default, default)),
  461. #else
  462. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  463. #endif
  464. Expression.Constant(provider, typeof(IQueryProvider)),
  465. getEnumerator
  466. )
  467. );
  468. }
  469. #pragma warning disable 1591
  470. [EditorBrowsable(EditorBrowsableState.Never)]
  471. public static IEnumerable<TResult> Create<TResult>(Func<IEnumerator<TResult>> getEnumerator)
  472. {
  473. return EnumerableEx.Create(getEnumerator);
  474. }
  475. #pragma warning restore 1591
  476. /// <summary>
  477. /// Returns a sequence with a single element.
  478. /// </summary>
  479. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  480. /// <param name="provider">Query provider.</param>
  481. /// <param name="value">Single element of the resulting sequence.</param>
  482. /// <returns>Sequence with a single element.</returns>
  483. public static IQueryable<TResult> Return<TResult>(this IQueryProvider provider, TResult value)
  484. {
  485. if (provider == null)
  486. {
  487. throw new ArgumentNullException(nameof(provider));
  488. }
  489. return provider.CreateQuery<TResult>(
  490. Expression.Call(
  491. null,
  492. #if CRIPPLED_REFLECTION
  493. InfoOf(() => QueryableEx.Return<TResult>(default, default)),
  494. #else
  495. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  496. #endif
  497. Expression.Constant(provider, typeof(IQueryProvider)),
  498. Expression.Constant(value, typeof(TResult))
  499. )
  500. );
  501. }
  502. #pragma warning disable 1591
  503. [EditorBrowsable(EditorBrowsableState.Never)]
  504. public static /*!*/IQueryable<TResult> Return<TResult>(TResult value)
  505. {
  506. return EnumerableEx.Return(value).AsQueryable();
  507. }
  508. #pragma warning restore 1591
  509. /// <summary>
  510. /// Returns a sequence that throws an exception upon enumeration.
  511. /// </summary>
  512. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  513. /// <param name="provider">Query provider.</param>
  514. /// <param name="exception">Exception to throw upon enumerating the resulting sequence.</param>
  515. /// <returns>Sequence that throws the specified exception upon enumeration.</returns>
  516. public static IQueryable<TResult> Throw<TResult>(this IQueryProvider provider, Exception exception)
  517. {
  518. if (provider == null)
  519. {
  520. throw new ArgumentNullException(nameof(provider));
  521. }
  522. if (exception == null)
  523. {
  524. throw new ArgumentNullException(nameof(exception));
  525. }
  526. return provider.CreateQuery<TResult>(
  527. Expression.Call(
  528. null,
  529. #if CRIPPLED_REFLECTION
  530. InfoOf(() => QueryableEx.Throw<TResult>(default, default)),
  531. #else
  532. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  533. #endif
  534. Expression.Constant(provider, typeof(IQueryProvider)),
  535. Expression.Constant(exception, typeof(Exception))
  536. )
  537. );
  538. }
  539. #pragma warning disable 1591
  540. [EditorBrowsable(EditorBrowsableState.Never)]
  541. public static /*!*/IQueryable<TResult> Throw<TResult>(Exception exception)
  542. {
  543. return EnumerableEx.Throw<TResult>(exception).AsQueryable();
  544. }
  545. #pragma warning restore 1591
  546. /// <summary>
  547. /// Creates an enumerable sequence based on an enumerable factory function.
  548. /// </summary>
  549. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  550. /// <param name="provider">Query provider.</param>
  551. /// <param name="enumerableFactory">Enumerable factory function.</param>
  552. /// <returns>Sequence that will invoke the enumerable factory upon a call to GetEnumerator.</returns>
  553. public static IQueryable<TResult> Defer<TResult>(this IQueryProvider provider, Expression<Func<IEnumerable<TResult>>> enumerableFactory)
  554. {
  555. if (provider == null)
  556. {
  557. throw new ArgumentNullException(nameof(provider));
  558. }
  559. if (enumerableFactory == null)
  560. {
  561. throw new ArgumentNullException(nameof(enumerableFactory));
  562. }
  563. return provider.CreateQuery<TResult>(
  564. Expression.Call(
  565. null,
  566. #if CRIPPLED_REFLECTION
  567. InfoOf(() => QueryableEx.Defer<TResult>(default, default)),
  568. #else
  569. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  570. #endif
  571. Expression.Constant(provider, typeof(IQueryProvider)),
  572. enumerableFactory
  573. )
  574. );
  575. }
  576. #pragma warning disable 1591
  577. [EditorBrowsable(EditorBrowsableState.Never)]
  578. public static /*!*/IQueryable<TResult> Defer<TResult>(Func<IEnumerable<TResult>> enumerableFactory)
  579. {
  580. return EnumerableEx.Defer(enumerableFactory).AsQueryable();
  581. }
  582. #pragma warning restore 1591
  583. /// <summary>
  584. /// Generates a sequence by mimicking a for loop.
  585. /// </summary>
  586. /// <typeparam name="TState">State type.</typeparam>
  587. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  588. /// <param name="provider">Query provider.</param>
  589. /// <param name="initialState">Initial state of the generator loop.</param>
  590. /// <param name="condition">Loop condition.</param>
  591. /// <param name="iterate">State update function to run after every iteration of the generator loop.</param>
  592. /// <param name="resultSelector">Result selector to compute resulting sequence elements.</param>
  593. /// <returns>Sequence obtained by running the generator loop, yielding computed elements.</returns>
  594. public static IQueryable<TResult> Generate<TState, TResult>(this IQueryProvider provider, TState initialState, Expression<Func<TState, bool>> condition, Expression<Func<TState, TState>> iterate, Expression<Func<TState, TResult>> resultSelector)
  595. {
  596. if (provider == null)
  597. {
  598. throw new ArgumentNullException(nameof(provider));
  599. }
  600. if (condition == null)
  601. {
  602. throw new ArgumentNullException(nameof(condition));
  603. }
  604. if (iterate == null)
  605. {
  606. throw new ArgumentNullException(nameof(iterate));
  607. }
  608. if (resultSelector == null)
  609. {
  610. throw new ArgumentNullException(nameof(resultSelector));
  611. }
  612. return provider.CreateQuery<TResult>(
  613. Expression.Call(
  614. null,
  615. #if CRIPPLED_REFLECTION
  616. InfoOf(() => QueryableEx.Generate<TState, TResult>(default, default, default, default, default)),
  617. #else
  618. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TState), typeof(TResult)),
  619. #endif
  620. Expression.Constant(provider, typeof(IQueryProvider)),
  621. Expression.Constant(initialState),
  622. condition,
  623. iterate,
  624. resultSelector
  625. )
  626. );
  627. }
  628. #pragma warning disable 1591
  629. [EditorBrowsable(EditorBrowsableState.Never)]
  630. public static /*!*/IQueryable<TResult> Generate<TState, TResult>(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector)
  631. {
  632. return EnumerableEx.Generate(initialState, condition, iterate, resultSelector).AsQueryable();
  633. }
  634. #pragma warning restore 1591
  635. /// <summary>
  636. /// Generates a sequence that's dependent on a resource object whose lifetime is determined by the sequence usage duration.
  637. /// </summary>
  638. /// <typeparam name="TSource">Source element type.</typeparam>
  639. /// <typeparam name="TResource">Resource type.</typeparam>
  640. /// <param name="provider">Query provider.</param>
  641. /// <param name="resourceFactory">Resource factory function.</param>
  642. /// <param name="enumerableFactory">Enumerable factory function, having access to the obtained resource.</param>
  643. /// <returns>Sequence whose use controls the lifetime of the associated obtained resource.</returns>
  644. public static IQueryable<TSource> Using<TSource, TResource>(this IQueryProvider provider, Expression<Func<TResource>> resourceFactory, Expression<Func<TResource, IEnumerable<TSource>>> enumerableFactory) where TResource : IDisposable
  645. {
  646. if (provider == null)
  647. {
  648. throw new ArgumentNullException(nameof(provider));
  649. }
  650. if (resourceFactory == null)
  651. {
  652. throw new ArgumentNullException(nameof(resourceFactory));
  653. }
  654. if (enumerableFactory == null)
  655. {
  656. throw new ArgumentNullException(nameof(enumerableFactory));
  657. }
  658. return provider.CreateQuery<TSource>(
  659. Expression.Call(
  660. null,
  661. #if CRIPPLED_REFLECTION
  662. InfoOf(() => QueryableEx.Using<TSource, TResource>(default, default, default)),
  663. #else
  664. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResource)),
  665. #endif
  666. Expression.Constant(provider, typeof(IQueryProvider)),
  667. resourceFactory,
  668. enumerableFactory
  669. )
  670. );
  671. }
  672. #pragma warning disable 1591
  673. [EditorBrowsable(EditorBrowsableState.Never)]
  674. public static /*!*/IQueryable<TSource> Using<TSource, TResource>(Func<TResource> resourceFactory, Func<TResource, IEnumerable<TSource>> enumerableFactory) where TResource : IDisposable
  675. {
  676. return EnumerableEx.Using(resourceFactory, enumerableFactory).AsQueryable();
  677. }
  678. #pragma warning restore 1591
  679. /// <summary>
  680. /// Generates a sequence by repeating the given value infinitely.
  681. /// </summary>
  682. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  683. /// <param name="provider">Query provider.</param>
  684. /// <param name="value">Value to repeat in the resulting sequence.</param>
  685. /// <returns>Sequence repeating the given value infinitely.</returns>
  686. public static IEnumerable<TResult> Repeat<TResult>(this IQueryProvider provider, TResult value)
  687. {
  688. if (provider == null)
  689. {
  690. throw new ArgumentNullException(nameof(provider));
  691. }
  692. return provider.CreateQuery<TResult>(
  693. Expression.Call(
  694. null,
  695. #if CRIPPLED_REFLECTION
  696. InfoOf(() => QueryableEx.Repeat<TResult>(default, default(TResult))),
  697. #else
  698. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  699. #endif
  700. Expression.Constant(provider, typeof(IQueryProvider)),
  701. Expression.Constant(value, typeof(TResult))
  702. )
  703. );
  704. }
  705. #pragma warning disable 1591
  706. [EditorBrowsable(EditorBrowsableState.Never)]
  707. public static /*!*/IQueryable<TResult> Repeat<TResult>(TResult value)
  708. {
  709. return EnumerableEx.Repeat(value).AsQueryable();
  710. }
  711. #pragma warning restore 1591
  712. /// <summary>
  713. /// Creates a sequence that corresponds to the source sequence, concatenating it with the sequence resulting from calling an exception handler function in case of an error.
  714. /// </summary>
  715. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  716. /// <typeparam name="TException">Exception type to catch.</typeparam>
  717. /// <param name="source">Source sequence.</param>
  718. /// <param name="handler">Handler to invoke when an exception of the specified type occurs.</param>
  719. /// <returns>Source sequence, concatenated with an exception handler result sequence in case of an error.</returns>
  720. public static IQueryable<TSource> Catch<TSource, TException>(this IQueryable<TSource> source, Expression<Func<TException, IEnumerable<TSource>>> handler)
  721. where TException : Exception
  722. {
  723. if (source == null)
  724. {
  725. throw new ArgumentNullException(nameof(source));
  726. }
  727. if (handler == null)
  728. {
  729. throw new ArgumentNullException(nameof(handler));
  730. }
  731. return source.Provider.CreateQuery<TSource>(
  732. Expression.Call(
  733. null,
  734. #if CRIPPLED_REFLECTION
  735. InfoOf(() => QueryableEx.Catch<TSource, TException>(default, default)),
  736. #else
  737. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TException)),
  738. #endif
  739. source.Expression,
  740. handler
  741. )
  742. );
  743. }
  744. #pragma warning disable 1591
  745. [EditorBrowsable(EditorBrowsableState.Never)]
  746. public static IEnumerable<TSource> Catch<TSource, TException>(IEnumerable<TSource> source, Func<TException, IEnumerable<TSource>> handler)
  747. where TException : Exception
  748. {
  749. return EnumerableEx.Catch(source, handler);
  750. }
  751. #pragma warning restore 1591
  752. /// <summary>
  753. /// Creates a sequence by concatenating source sequences until a source sequence completes successfully.
  754. /// </summary>
  755. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  756. /// <param name="sources">Source sequences.</param>
  757. /// <returns>Sequence that continues to concatenate source sequences while errors occur.</returns>
  758. public static IQueryable<TSource> Catch<TSource>(this IQueryable<IEnumerable<TSource>> sources)
  759. {
  760. if (sources == null)
  761. {
  762. throw new ArgumentNullException(nameof(sources));
  763. }
  764. return sources.Provider.CreateQuery<TSource>(
  765. Expression.Call(
  766. null,
  767. #if CRIPPLED_REFLECTION
  768. InfoOf(() => QueryableEx.Catch<TSource>(default(IQueryable<IEnumerable<TSource>>))),
  769. #else
  770. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  771. #endif
  772. sources.Expression
  773. )
  774. );
  775. }
  776. #pragma warning disable 1591
  777. [EditorBrowsable(EditorBrowsableState.Never)]
  778. public static IEnumerable<TSource> Catch<TSource>(IEnumerable<IEnumerable<TSource>> sources)
  779. {
  780. return EnumerableEx.Catch(sources);
  781. }
  782. #pragma warning restore 1591
  783. /// <summary>
  784. /// Creates a sequence by concatenating source sequences until a source sequence completes successfully.
  785. /// </summary>
  786. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  787. /// <param name="provider">Query provider.</param>
  788. /// <param name="sources">Source sequences.</param>
  789. /// <returns>Sequence that continues to concatenate source sequences while errors occur.</returns>
  790. public static IQueryable<TSource> Catch<TSource>(this IQueryProvider provider, params IEnumerable<TSource>[] sources)
  791. {
  792. if (provider == null)
  793. {
  794. throw new ArgumentNullException(nameof(provider));
  795. }
  796. if (sources == null)
  797. {
  798. throw new ArgumentNullException(nameof(sources));
  799. }
  800. return provider.CreateQuery<TSource>(
  801. Expression.Call(
  802. null,
  803. #if CRIPPLED_REFLECTION
  804. InfoOf(() => QueryableEx.Catch<TSource>(default, default(IEnumerable<TSource>[]))),
  805. #else
  806. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  807. #endif
  808. Expression.Constant(provider, typeof(IQueryProvider)),
  809. GetSourceExpression(sources)
  810. )
  811. );
  812. }
  813. #pragma warning disable 1591
  814. [EditorBrowsable(EditorBrowsableState.Never)]
  815. public static /*!*/IQueryable<TSource> Catch<TSource>(params IEnumerable<TSource>[] sources)
  816. {
  817. return EnumerableEx.Catch(sources).AsQueryable();
  818. }
  819. #pragma warning restore 1591
  820. /// <summary>
  821. /// Creates a sequence that returns the elements of the first sequence, switching to the second in case of an error.
  822. /// </summary>
  823. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  824. /// <param name="first">First sequence.</param>
  825. /// <param name="second">Second sequence, concatenated to the result in case the first sequence completes exceptionally.</param>
  826. /// <returns>The first sequence, followed by the second sequence in case an error is produced.</returns>
  827. public static IQueryable<TSource> Catch<TSource>(this IQueryable<TSource> first, IEnumerable<TSource> second)
  828. {
  829. if (first == null)
  830. {
  831. throw new ArgumentNullException(nameof(first));
  832. }
  833. if (second == null)
  834. {
  835. throw new ArgumentNullException(nameof(second));
  836. }
  837. return first.Provider.CreateQuery<TSource>(
  838. Expression.Call(
  839. null,
  840. #if CRIPPLED_REFLECTION
  841. InfoOf(() => QueryableEx.Catch<TSource>(default(IQueryable<TSource>), default)),
  842. #else
  843. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  844. #endif
  845. first.Expression,
  846. GetSourceExpression(second)
  847. )
  848. );
  849. }
  850. #pragma warning disable 1591
  851. [EditorBrowsable(EditorBrowsableState.Never)]
  852. public static IEnumerable<TSource> Catch<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second)
  853. {
  854. return EnumerableEx.Catch(first, second);
  855. }
  856. #pragma warning restore 1591
  857. /// <summary>
  858. /// Creates a sequence whose termination or disposal of an enumerator causes a finally action to be executed.
  859. /// </summary>
  860. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  861. /// <param name="source">Source sequence.</param>
  862. /// <param name="finallyAction">Action to run upon termination of the sequence, or when an enumerator is disposed.</param>
  863. /// <returns>Source sequence with guarantees on the invocation of the finally action.</returns>
  864. public static IQueryable<TSource> Finally<TSource>(this IQueryable<TSource> source, Expression<Action> finallyAction)
  865. {
  866. if (source == null)
  867. {
  868. throw new ArgumentNullException(nameof(source));
  869. }
  870. if (finallyAction == null)
  871. {
  872. throw new ArgumentNullException(nameof(finallyAction));
  873. }
  874. return source.Provider.CreateQuery<TSource>(
  875. Expression.Call(
  876. null,
  877. #if CRIPPLED_REFLECTION
  878. InfoOf(() => QueryableEx.Finally<TSource>(default, default)),
  879. #else
  880. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  881. #endif
  882. source.Expression,
  883. finallyAction
  884. )
  885. );
  886. }
  887. #pragma warning disable 1591
  888. [EditorBrowsable(EditorBrowsableState.Never)]
  889. public static IEnumerable<TSource> Finally<TSource>(IEnumerable<TSource> source, Action finallyAction)
  890. {
  891. return EnumerableEx.Finally(source, finallyAction);
  892. }
  893. #pragma warning restore 1591
  894. /// <summary>
  895. /// Creates a sequence that concatenates both given sequences, regardless of whether an error occurs.
  896. /// </summary>
  897. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  898. /// <param name="first">First sequence.</param>
  899. /// <param name="second">Second sequence.</param>
  900. /// <returns>Sequence concatenating the elements of both sequences, ignoring errors.</returns>
  901. public static IQueryable<TSource> OnErrorResumeNext<TSource>(this IQueryable<TSource> first, IEnumerable<TSource> second)
  902. {
  903. if (first == null)
  904. {
  905. throw new ArgumentNullException(nameof(first));
  906. }
  907. if (second == null)
  908. {
  909. throw new ArgumentNullException(nameof(second));
  910. }
  911. return first.Provider.CreateQuery<TSource>(
  912. Expression.Call(
  913. null,
  914. #if CRIPPLED_REFLECTION
  915. InfoOf(() => QueryableEx.OnErrorResumeNext<TSource>(default(IQueryable<TSource>), default)),
  916. #else
  917. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  918. #endif
  919. first.Expression,
  920. GetSourceExpression(second)
  921. )
  922. );
  923. }
  924. #pragma warning disable 1591
  925. [EditorBrowsable(EditorBrowsableState.Never)]
  926. public static IEnumerable<TSource> OnErrorResumeNext<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second)
  927. {
  928. return EnumerableEx.OnErrorResumeNext(first, second);
  929. }
  930. #pragma warning restore 1591
  931. /// <summary>
  932. /// Creates a sequence that concatenates the given sequences, regardless of whether an error occurs in any of the sequences.
  933. /// </summary>
  934. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  935. /// <param name="provider">Query provider.</param>
  936. /// <param name="sources">Source sequences.</param>
  937. /// <returns>Sequence concatenating the elements of the given sequences, ignoring errors.</returns>
  938. public static IEnumerable<TSource> OnErrorResumeNext<TSource>(this IQueryProvider provider, params IEnumerable<TSource>[] sources)
  939. {
  940. if (provider == null)
  941. {
  942. throw new ArgumentNullException(nameof(provider));
  943. }
  944. if (sources == null)
  945. {
  946. throw new ArgumentNullException(nameof(sources));
  947. }
  948. return provider.CreateQuery<TSource>(
  949. Expression.Call(
  950. null,
  951. #if CRIPPLED_REFLECTION
  952. InfoOf(() => QueryableEx.OnErrorResumeNext<TSource>(default, default(IEnumerable<TSource>[]))),
  953. #else
  954. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  955. #endif
  956. Expression.Constant(provider, typeof(IQueryProvider)),
  957. GetSourceExpression(sources)
  958. )
  959. );
  960. }
  961. #pragma warning disable 1591
  962. [EditorBrowsable(EditorBrowsableState.Never)]
  963. public static /*!*/IQueryable<TSource> OnErrorResumeNext<TSource>(params IEnumerable<TSource>[] sources)
  964. {
  965. return EnumerableEx.OnErrorResumeNext(sources).AsQueryable();
  966. }
  967. #pragma warning restore 1591
  968. /// <summary>
  969. /// Creates a sequence that concatenates the given sequences, regardless of whether an error occurs in any of the sequences.
  970. /// </summary>
  971. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  972. /// <param name="sources">Source sequences.</param>
  973. /// <returns>Sequence concatenating the elements of the given sequences, ignoring errors.</returns>
  974. public static IQueryable<TSource> OnErrorResumeNext<TSource>(this IQueryable<IEnumerable<TSource>> sources)
  975. {
  976. if (sources == null)
  977. {
  978. throw new ArgumentNullException(nameof(sources));
  979. }
  980. return sources.Provider.CreateQuery<TSource>(
  981. Expression.Call(
  982. null,
  983. #if CRIPPLED_REFLECTION
  984. InfoOf(() => QueryableEx.OnErrorResumeNext<TSource>(default(IQueryable<IEnumerable<TSource>>))),
  985. #else
  986. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  987. #endif
  988. sources.Expression
  989. )
  990. );
  991. }
  992. #pragma warning disable 1591
  993. [EditorBrowsable(EditorBrowsableState.Never)]
  994. public static IEnumerable<TSource> OnErrorResumeNext<TSource>(IEnumerable<IEnumerable<TSource>> sources)
  995. {
  996. return EnumerableEx.OnErrorResumeNext(sources);
  997. }
  998. #pragma warning restore 1591
  999. /// <summary>
  1000. /// Creates a sequence that retries enumerating the source sequence as long as an error occurs.
  1001. /// </summary>
  1002. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1003. /// <param name="source">Source sequence.</param>
  1004. /// <returns>Sequence concatenating the results of the source sequence as long as an error occurs.</returns>
  1005. public static IQueryable<TSource> Retry<TSource>(this IQueryable<TSource> source)
  1006. {
  1007. if (source == null)
  1008. {
  1009. throw new ArgumentNullException(nameof(source));
  1010. }
  1011. return source.Provider.CreateQuery<TSource>(
  1012. Expression.Call(
  1013. null,
  1014. #if CRIPPLED_REFLECTION
  1015. InfoOf(() => QueryableEx.Retry<TSource>(default)),
  1016. #else
  1017. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1018. #endif
  1019. source.Expression
  1020. )
  1021. );
  1022. }
  1023. #pragma warning disable 1591
  1024. [EditorBrowsable(EditorBrowsableState.Never)]
  1025. public static IEnumerable<TSource> Retry<TSource>(IEnumerable<TSource> source)
  1026. {
  1027. return EnumerableEx.Retry(source);
  1028. }
  1029. #pragma warning restore 1591
  1030. /// <summary>
  1031. /// Creates a sequence that retries enumerating the source sequence as long as an error occurs, with the specified maximum number of retries.
  1032. /// </summary>
  1033. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1034. /// <param name="source">Source sequence.</param>
  1035. /// <param name="retryCount">Maximum number of retries.</param>
  1036. /// <returns>Sequence concatenating the results of the source sequence as long as an error occurs.</returns>
  1037. public static IQueryable<TSource> Retry<TSource>(this IQueryable<TSource> source, int retryCount)
  1038. {
  1039. if (source == null)
  1040. {
  1041. throw new ArgumentNullException(nameof(source));
  1042. }
  1043. return source.Provider.CreateQuery<TSource>(
  1044. Expression.Call(
  1045. null,
  1046. #if CRIPPLED_REFLECTION
  1047. InfoOf(() => QueryableEx.Retry<TSource>(default, default)),
  1048. #else
  1049. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1050. #endif
  1051. source.Expression,
  1052. Expression.Constant(retryCount, typeof(int))
  1053. )
  1054. );
  1055. }
  1056. #pragma warning disable 1591
  1057. [EditorBrowsable(EditorBrowsableState.Never)]
  1058. public static IEnumerable<TSource> Retry<TSource>(IEnumerable<TSource> source, int retryCount)
  1059. {
  1060. return EnumerableEx.Retry(source, retryCount);
  1061. }
  1062. #pragma warning restore 1591
  1063. /// <summary>
  1064. /// Generates an enumerable sequence by repeating a source sequence as long as the given loop condition holds.
  1065. /// </summary>
  1066. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1067. /// <param name="provider">Query provider.</param>
  1068. /// <param name="condition">Loop condition.</param>
  1069. /// <param name="source">Sequence to repeat while the condition evaluates true.</param>
  1070. /// <returns>Sequence generated by repeating the given sequence while the condition evaluates to true.</returns>
  1071. public static IQueryable<TResult> While<TResult>(this IQueryProvider provider, Expression<Func<bool>> condition, IEnumerable<TResult> source)
  1072. {
  1073. if (provider == null)
  1074. {
  1075. throw new ArgumentNullException(nameof(provider));
  1076. }
  1077. if (condition == null)
  1078. {
  1079. throw new ArgumentNullException(nameof(condition));
  1080. }
  1081. if (source == null)
  1082. {
  1083. throw new ArgumentNullException(nameof(source));
  1084. }
  1085. return provider.CreateQuery<TResult>(
  1086. Expression.Call(
  1087. null,
  1088. #if CRIPPLED_REFLECTION
  1089. InfoOf(() => QueryableEx.While<TResult>(default, default, default)),
  1090. #else
  1091. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  1092. #endif
  1093. Expression.Constant(provider, typeof(IQueryProvider)),
  1094. condition,
  1095. GetSourceExpression(source)
  1096. )
  1097. );
  1098. }
  1099. #pragma warning disable 1591
  1100. [EditorBrowsable(EditorBrowsableState.Never)]
  1101. public static /*!*/IQueryable<TResult> While<TResult>(Func<bool> condition, IEnumerable<TResult> source)
  1102. {
  1103. return EnumerableEx.While(condition, source).AsQueryable();
  1104. }
  1105. #pragma warning restore 1591
  1106. /// <summary>
  1107. /// Returns an enumerable sequence based on the evaluation result of the given condition.
  1108. /// </summary>
  1109. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1110. /// <param name="provider">Query provider.</param>
  1111. /// <param name="condition">Condition to evaluate.</param>
  1112. /// <param name="thenSource">Sequence to return in case the condition evaluates true.</param>
  1113. /// <param name="elseSource">Sequence to return in case the condition evaluates false.</param>
  1114. /// <returns>Either of the two input sequences based on the result of evaluating the condition.</returns>
  1115. public static IQueryable<TResult> If<TResult>(this IQueryProvider provider, Expression<Func<bool>> condition, IEnumerable<TResult> thenSource, IEnumerable<TResult> elseSource)
  1116. {
  1117. if (provider == null)
  1118. {
  1119. throw new ArgumentNullException(nameof(provider));
  1120. }
  1121. if (condition == null)
  1122. {
  1123. throw new ArgumentNullException(nameof(condition));
  1124. }
  1125. if (thenSource == null)
  1126. {
  1127. throw new ArgumentNullException(nameof(thenSource));
  1128. }
  1129. if (elseSource == null)
  1130. {
  1131. throw new ArgumentNullException(nameof(elseSource));
  1132. }
  1133. return provider.CreateQuery<TResult>(
  1134. Expression.Call(
  1135. null,
  1136. #if CRIPPLED_REFLECTION
  1137. InfoOf(() => QueryableEx.If<TResult>(default, default, default, default)),
  1138. #else
  1139. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  1140. #endif
  1141. Expression.Constant(provider, typeof(IQueryProvider)),
  1142. condition,
  1143. GetSourceExpression(thenSource),
  1144. GetSourceExpression(elseSource)
  1145. )
  1146. );
  1147. }
  1148. #pragma warning disable 1591
  1149. [EditorBrowsable(EditorBrowsableState.Never)]
  1150. public static /*!*/IQueryable<TResult> If<TResult>(Func<bool> condition, IEnumerable<TResult> thenSource, IEnumerable<TResult> elseSource)
  1151. {
  1152. return EnumerableEx.If(condition, thenSource, elseSource).AsQueryable();
  1153. }
  1154. #pragma warning restore 1591
  1155. /// <summary>
  1156. /// Returns an enumerable sequence if the evaluation result of the given condition is true, otherwise returns an empty sequence.
  1157. /// </summary>
  1158. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1159. /// <param name="provider">Query provider.</param>
  1160. /// <param name="condition">Condition to evaluate.</param>
  1161. /// <param name="thenSource">Sequence to return in case the condition evaluates true.</param>
  1162. /// <returns>The given input sequence if the condition evaluates true; otherwise, an empty sequence.</returns>
  1163. public static IQueryable<TResult> If<TResult>(this IQueryProvider provider, Expression<Func<bool>> condition, IEnumerable<TResult> thenSource)
  1164. {
  1165. if (provider == null)
  1166. {
  1167. throw new ArgumentNullException(nameof(provider));
  1168. }
  1169. if (condition == null)
  1170. {
  1171. throw new ArgumentNullException(nameof(condition));
  1172. }
  1173. if (thenSource == null)
  1174. {
  1175. throw new ArgumentNullException(nameof(thenSource));
  1176. }
  1177. return provider.CreateQuery<TResult>(
  1178. Expression.Call(
  1179. null,
  1180. #if CRIPPLED_REFLECTION
  1181. InfoOf(() => QueryableEx.If<TResult>(default, default(Expression<Func<bool>>), default)),
  1182. #else
  1183. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  1184. #endif
  1185. Expression.Constant(provider, typeof(IQueryProvider)),
  1186. condition,
  1187. GetSourceExpression(thenSource)
  1188. )
  1189. );
  1190. }
  1191. #pragma warning disable 1591
  1192. [EditorBrowsable(EditorBrowsableState.Never)]
  1193. public static /*!*/IQueryable<TResult> If<TResult>(Func<bool> condition, IEnumerable<TResult> thenSource)
  1194. {
  1195. return EnumerableEx.If(condition, thenSource).AsQueryable();
  1196. }
  1197. #pragma warning restore 1591
  1198. /// <summary>
  1199. /// Generates an enumerable sequence by repeating a source sequence as long as the given loop postcondition holds.
  1200. /// </summary>
  1201. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1202. /// <param name="source">Source sequence to repeat while the condition evaluates true.</param>
  1203. /// <param name="condition">Loop condition.</param>
  1204. /// <returns>Sequence generated by repeating the given sequence until the condition evaluates to false.</returns>
  1205. public static IQueryable<TResult> DoWhile<TResult>(this IQueryable<TResult> source, Expression<Func<bool>> condition)
  1206. {
  1207. if (source == null)
  1208. {
  1209. throw new ArgumentNullException(nameof(source));
  1210. }
  1211. if (condition == null)
  1212. {
  1213. throw new ArgumentNullException(nameof(condition));
  1214. }
  1215. return source.Provider.CreateQuery<TResult>(
  1216. Expression.Call(
  1217. null,
  1218. #if CRIPPLED_REFLECTION
  1219. InfoOf(() => QueryableEx.DoWhile<TResult>(default, default)),
  1220. #else
  1221. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  1222. #endif
  1223. source.Expression,
  1224. condition
  1225. )
  1226. );
  1227. }
  1228. #pragma warning disable 1591
  1229. [EditorBrowsable(EditorBrowsableState.Never)]
  1230. public static IEnumerable<TResult> DoWhile<TResult>(IEnumerable<TResult> source, Func<bool> condition)
  1231. {
  1232. return EnumerableEx.DoWhile(source, condition);
  1233. }
  1234. #pragma warning restore 1591
  1235. /// <summary>
  1236. /// Returns a sequence from a dictionary based on the result of evaluating a selector function.
  1237. /// </summary>
  1238. /// <typeparam name="TValue">Type of the selector value.</typeparam>
  1239. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1240. /// <param name="provider">Query provider.</param>
  1241. /// <param name="selector">Selector function used to pick a sequence from the given sources.</param>
  1242. /// <param name="sources">Dictionary mapping selector values onto resulting sequences.</param>
  1243. /// <returns>The source sequence corresponding with the evaluated selector value; otherwise, an empty sequence.</returns>
  1244. public static IQueryable<TResult> Case<TValue, TResult>(this IQueryProvider provider, Expression<Func<TValue>> selector, IDictionary<TValue, IEnumerable<TResult>> sources)
  1245. {
  1246. if (provider == null)
  1247. {
  1248. throw new ArgumentNullException(nameof(provider));
  1249. }
  1250. if (selector == null)
  1251. {
  1252. throw new ArgumentNullException(nameof(selector));
  1253. }
  1254. if (sources == null)
  1255. {
  1256. throw new ArgumentNullException(nameof(sources));
  1257. }
  1258. return provider.CreateQuery<TResult>(
  1259. Expression.Call(
  1260. null,
  1261. #if CRIPPLED_REFLECTION
  1262. InfoOf(() => QueryableEx.Case<TValue, TResult>(default, default, default(IDictionary<TValue, IEnumerable<TResult>>))),
  1263. #else
  1264. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TValue), typeof(TResult)),
  1265. #endif
  1266. selector,
  1267. Expression.Constant(sources, typeof(IDictionary<TValue, IEnumerable<TResult>>))
  1268. )
  1269. );
  1270. }
  1271. #pragma warning disable 1591
  1272. [EditorBrowsable(EditorBrowsableState.Never)]
  1273. public static /*!*/IQueryable<TResult> Case<TValue, TResult>(Func<TValue> selector, IDictionary<TValue, IEnumerable<TResult>> sources)
  1274. {
  1275. return EnumerableEx.Case(selector, sources).AsQueryable();
  1276. }
  1277. #pragma warning restore 1591
  1278. /// <summary>
  1279. /// Returns a sequence from a dictionary based on the result of evaluating a selector function, also specifying a default sequence.
  1280. /// </summary>
  1281. /// <typeparam name="TValue">Type of the selector value.</typeparam>
  1282. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1283. /// <param name="provider">Query provider.</param>
  1284. /// <param name="selector">Selector function used to pick a sequence from the given sources.</param>
  1285. /// <param name="sources">Dictionary mapping selector values onto resulting sequences.</param>
  1286. /// <param name="defaultSource">Default sequence to return in case there's no corresponding source for the computed selector value.</param>
  1287. /// <returns>The source sequence corresponding with the evaluated selector value; otherwise, the default source.</returns>
  1288. public static IQueryable<TResult> Case<TValue, TResult>(this IQueryProvider provider, Expression<Func<TValue>> selector, IDictionary<TValue, IEnumerable<TResult>> sources, IEnumerable<TResult> defaultSource)
  1289. {
  1290. if (provider == null)
  1291. {
  1292. throw new ArgumentNullException(nameof(provider));
  1293. }
  1294. if (selector == null)
  1295. {
  1296. throw new ArgumentNullException(nameof(selector));
  1297. }
  1298. if (sources == null)
  1299. {
  1300. throw new ArgumentNullException(nameof(sources));
  1301. }
  1302. if (defaultSource == null)
  1303. {
  1304. throw new ArgumentNullException(nameof(defaultSource));
  1305. }
  1306. return provider.CreateQuery<TResult>(
  1307. Expression.Call(
  1308. null,
  1309. #if CRIPPLED_REFLECTION
  1310. InfoOf(() => QueryableEx.Case<TValue, TResult>(default, default, default, default)),
  1311. #else
  1312. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TValue), typeof(TResult)),
  1313. #endif
  1314. selector,
  1315. Expression.Constant(sources, typeof(IDictionary<TValue, IEnumerable<TResult>>))
  1316. )
  1317. );
  1318. }
  1319. #pragma warning disable 1591
  1320. [EditorBrowsable(EditorBrowsableState.Never)]
  1321. public static /*!*/IQueryable<TResult> Case<TValue, TResult>(Func<TValue> selector, IDictionary<TValue, IEnumerable<TResult>> sources, IEnumerable<TResult> defaultSource)
  1322. {
  1323. return EnumerableEx.Case(selector, sources, defaultSource).AsQueryable();
  1324. }
  1325. #pragma warning restore 1591
  1326. /// <summary>
  1327. /// Generates a sequence by enumerating a source sequence, mapping its elements on result sequences, and concatenating those sequences.
  1328. /// </summary>
  1329. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1330. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  1331. /// <param name="provider">Query provider.</param>
  1332. /// <param name="source">Source sequence.</param>
  1333. /// <param name="resultSelector">Result selector to evaluate for each iteration over the source.</param>
  1334. /// <returns>Sequence concatenating the inner sequences that result from evaluating the result selector on elements from the source.</returns>
  1335. public static IQueryable<TResult> For<TSource, TResult>(this IQueryProvider provider, IEnumerable<TSource> source, Expression<Func<TSource, IEnumerable<TResult>>> resultSelector)
  1336. {
  1337. if (provider == null)
  1338. {
  1339. throw new ArgumentNullException(nameof(provider));
  1340. }
  1341. if (source == null)
  1342. {
  1343. throw new ArgumentNullException(nameof(source));
  1344. }
  1345. if (resultSelector == null)
  1346. {
  1347. throw new ArgumentNullException(nameof(resultSelector));
  1348. }
  1349. return provider.CreateQuery<TResult>(
  1350. Expression.Call(
  1351. null,
  1352. #if CRIPPLED_REFLECTION
  1353. InfoOf(() => QueryableEx.For<TSource, TResult>(default, default, default)),
  1354. #else
  1355. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
  1356. #endif
  1357. GetSourceExpression(source),
  1358. resultSelector
  1359. )
  1360. );
  1361. }
  1362. #pragma warning disable 1591
  1363. [EditorBrowsable(EditorBrowsableState.Never)]
  1364. public static /*!*/IQueryable<TResult> For<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> resultSelector)
  1365. {
  1366. return EnumerableEx.For(source, resultSelector).AsQueryable();
  1367. }
  1368. #pragma warning restore 1591
  1369. /// <summary>
  1370. /// Concatenates the input sequences.
  1371. /// </summary>
  1372. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1373. /// <param name="sources">Source sequences.</param>
  1374. /// <returns>Sequence with the elements of the source sequences concatenated.</returns>
  1375. public static IQueryable<TSource> Concat<TSource>(this IQueryable<IEnumerable<TSource>> sources)
  1376. {
  1377. if (sources == null)
  1378. {
  1379. throw new ArgumentNullException(nameof(sources));
  1380. }
  1381. return sources.Provider.CreateQuery<TSource>(
  1382. Expression.Call(
  1383. null,
  1384. #if CRIPPLED_REFLECTION
  1385. InfoOf(() => QueryableEx.Concat<TSource>(default(IQueryable<IEnumerable<TSource>>))),
  1386. #else
  1387. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1388. #endif
  1389. GetSourceExpression(sources)
  1390. )
  1391. );
  1392. }
  1393. #pragma warning disable 1591
  1394. [EditorBrowsable(EditorBrowsableState.Never)]
  1395. public static IEnumerable<TSource> Concat<TSource>(IEnumerable<IEnumerable<TSource>> sources)
  1396. {
  1397. return EnumerableEx.Concat(sources);
  1398. }
  1399. #pragma warning restore 1591
  1400. /// <summary>
  1401. /// Concatenates the input sequences.
  1402. /// </summary>
  1403. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1404. /// <param name="provider">Query provider.</param>
  1405. /// <param name="sources">Source sequences.</param>
  1406. /// <returns>Sequence with the elements of the source sequences concatenated.</returns>
  1407. public static IQueryable<TSource> Concat<TSource>(this IQueryProvider provider, params IEnumerable<TSource>[] sources)
  1408. {
  1409. if (provider == null)
  1410. {
  1411. throw new ArgumentNullException(nameof(provider));
  1412. }
  1413. if (sources == null)
  1414. {
  1415. throw new ArgumentNullException(nameof(sources));
  1416. }
  1417. return provider.CreateQuery<TSource>(
  1418. Expression.Call(
  1419. null,
  1420. #if CRIPPLED_REFLECTION
  1421. InfoOf(() => QueryableEx.Concat<TSource>(default, default(IEnumerable<TSource>[]))),
  1422. #else
  1423. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1424. #endif
  1425. Expression.Constant(provider, typeof(IQueryProvider)),
  1426. GetSourceExpression(sources)
  1427. )
  1428. );
  1429. }
  1430. #pragma warning disable 1591
  1431. [EditorBrowsable(EditorBrowsableState.Never)]
  1432. public static /*!*/IQueryable<TSource> Concat<TSource>(params IEnumerable<TSource>[] sources)
  1433. {
  1434. return EnumerableEx.Concat(sources).AsQueryable();
  1435. }
  1436. #pragma warning restore 1591
  1437. /// <summary>
  1438. /// Projects each element of a sequence to an given sequence and flattens the resulting sequences into one sequence.
  1439. /// </summary>
  1440. /// <typeparam name="TSource">First source sequence element type.</typeparam>
  1441. /// <typeparam name="TOther">Second source sequence element type.</typeparam>
  1442. /// <param name="source">A sequence of values to project.</param>
  1443. /// <param name="other">Inner sequence each source sequence element is projected onto.</param>
  1444. /// <returns>Sequence flattening the sequences that result from projecting elements in the source sequence.</returns>
  1445. public static IQueryable<TOther> SelectMany<TSource, TOther>(this IQueryable<TSource> source, IEnumerable<TOther> other)
  1446. {
  1447. if (source == null)
  1448. {
  1449. throw new ArgumentNullException(nameof(source));
  1450. }
  1451. if (other == null)
  1452. {
  1453. throw new ArgumentNullException(nameof(other));
  1454. }
  1455. return source.Provider.CreateQuery<TOther>(
  1456. Expression.Call(
  1457. null,
  1458. #if CRIPPLED_REFLECTION
  1459. InfoOf(() => QueryableEx.SelectMany<TSource, TOther>(default, default)),
  1460. #else
  1461. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TOther)),
  1462. #endif
  1463. source.Expression,
  1464. GetSourceExpression(other)
  1465. )
  1466. );
  1467. }
  1468. #pragma warning disable 1591
  1469. [EditorBrowsable(EditorBrowsableState.Never)]
  1470. public static IEnumerable<TOther> SelectMany<TSource, TOther>(IEnumerable<TSource> source, IEnumerable<TOther> other)
  1471. {
  1472. return EnumerableEx.SelectMany(source, other);
  1473. }
  1474. #pragma warning restore 1591
  1475. /// <summary>
  1476. /// Hides the enumerable sequence object identity.
  1477. /// </summary>
  1478. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1479. /// <param name="source">Source sequence.</param>
  1480. /// <returns>Enumerable sequence with the same behavior as the original, but hiding the source object identity.</returns>
  1481. /// <remarks>AsQueryable doesn't hide the object identity, and simply acts as a cast to the IQueryable&lt;TSource&gt; interface.</remarks>
  1482. public static IQueryable<TSource> Hide<TSource>(this IQueryable<TSource> source)
  1483. {
  1484. if (source == null)
  1485. {
  1486. throw new ArgumentNullException(nameof(source));
  1487. }
  1488. return source.Provider.CreateQuery<TSource>(
  1489. Expression.Call(
  1490. null,
  1491. #if CRIPPLED_REFLECTION
  1492. InfoOf(() => QueryableEx.Hide<TSource>(default)),
  1493. #else
  1494. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1495. #endif
  1496. source.Expression
  1497. )
  1498. );
  1499. }
  1500. #pragma warning disable 1591
  1501. [EditorBrowsable(EditorBrowsableState.Never)]
  1502. public static IEnumerable<TSource> Hide<TSource>(IEnumerable<TSource> source)
  1503. {
  1504. return EnumerableEx.Hide(source);
  1505. }
  1506. #pragma warning restore 1591
  1507. /// <summary>
  1508. /// Lazily invokes an action for each value in the sequence.
  1509. /// </summary>
  1510. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1511. /// <param name="source">Source sequence.</param>
  1512. /// <param name="onNext">Action to invoke for each element.</param>
  1513. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  1514. public static IQueryable<TSource> Do<TSource>(this IQueryable<TSource> source, Expression<Action<TSource>> onNext)
  1515. {
  1516. if (source == null)
  1517. {
  1518. throw new ArgumentNullException(nameof(source));
  1519. }
  1520. if (onNext == null)
  1521. {
  1522. throw new ArgumentNullException(nameof(onNext));
  1523. }
  1524. return source.Provider.CreateQuery<TSource>(
  1525. Expression.Call(
  1526. null,
  1527. #if CRIPPLED_REFLECTION
  1528. InfoOf(() => QueryableEx.Do<TSource>(default, default(Expression<Action<TSource>>))),
  1529. #else
  1530. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1531. #endif
  1532. source.Expression,
  1533. onNext
  1534. )
  1535. );
  1536. }
  1537. #pragma warning disable 1591
  1538. [EditorBrowsable(EditorBrowsableState.Never)]
  1539. public static IEnumerable<TSource> Do<TSource>(IEnumerable<TSource> source, Action<TSource> onNext)
  1540. {
  1541. return EnumerableEx.Do(source, onNext);
  1542. }
  1543. #pragma warning restore 1591
  1544. /// <summary>
  1545. /// Lazily invokes an action for each value in the sequence, and executes an action for successful termination.
  1546. /// </summary>
  1547. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1548. /// <param name="source">Source sequence.</param>
  1549. /// <param name="onNext">Action to invoke for each element.</param>
  1550. /// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
  1551. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  1552. public static IQueryable<TSource> Do<TSource>(this IQueryable<TSource> source, Expression<Action<TSource>> onNext, Expression<Action> onCompleted)
  1553. {
  1554. if (source == null)
  1555. {
  1556. throw new ArgumentNullException(nameof(source));
  1557. }
  1558. if (onNext == null)
  1559. {
  1560. throw new ArgumentNullException(nameof(onNext));
  1561. }
  1562. if (onCompleted == null)
  1563. {
  1564. throw new ArgumentNullException(nameof(onCompleted));
  1565. }
  1566. return source.Provider.CreateQuery<TSource>(
  1567. Expression.Call(
  1568. null,
  1569. #if CRIPPLED_REFLECTION
  1570. InfoOf(() => QueryableEx.Do<TSource>(default, default, default(Expression<Action>))),
  1571. #else
  1572. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1573. #endif
  1574. source.Expression,
  1575. onNext,
  1576. onCompleted
  1577. )
  1578. );
  1579. }
  1580. #pragma warning disable 1591
  1581. [EditorBrowsable(EditorBrowsableState.Never)]
  1582. public static IEnumerable<TSource> Do<TSource>(IEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
  1583. {
  1584. return EnumerableEx.Do(source, onNext, onCompleted);
  1585. }
  1586. #pragma warning restore 1591
  1587. /// <summary>
  1588. /// Lazily invokes an action for each value in the sequence, and executes an action upon exceptional termination.
  1589. /// </summary>
  1590. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1591. /// <param name="source">Source sequence.</param>
  1592. /// <param name="onNext">Action to invoke for each element.</param>
  1593. /// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
  1594. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  1595. public static IQueryable<TSource> Do<TSource>(this IQueryable<TSource> source, Expression<Action<TSource>> onNext, Expression<Action<Exception>> onError)
  1596. {
  1597. if (source == null)
  1598. {
  1599. throw new ArgumentNullException(nameof(source));
  1600. }
  1601. if (onNext == null)
  1602. {
  1603. throw new ArgumentNullException(nameof(onNext));
  1604. }
  1605. if (onError == null)
  1606. {
  1607. throw new ArgumentNullException(nameof(onError));
  1608. }
  1609. return source.Provider.CreateQuery<TSource>(
  1610. Expression.Call(
  1611. null,
  1612. #if CRIPPLED_REFLECTION
  1613. InfoOf(() => QueryableEx.Do<TSource>(default, default, default(Expression<Action<Exception>>))),
  1614. #else
  1615. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1616. #endif
  1617. source.Expression,
  1618. onNext,
  1619. onError
  1620. )
  1621. );
  1622. }
  1623. #pragma warning disable 1591
  1624. [EditorBrowsable(EditorBrowsableState.Never)]
  1625. public static IEnumerable<TSource> Do<TSource>(IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
  1626. {
  1627. return EnumerableEx.Do(source, onNext, onError);
  1628. }
  1629. #pragma warning restore 1591
  1630. /// <summary>
  1631. /// Lazily invokes an action for each value in the sequence, and executes an action upon successful or exceptional termination.
  1632. /// </summary>
  1633. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1634. /// <param name="source">Source sequence.</param>
  1635. /// <param name="onNext">Action to invoke for each element.</param>
  1636. /// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
  1637. /// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
  1638. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  1639. public static IQueryable<TSource> Do<TSource>(this IQueryable<TSource> source, Expression<Action<TSource>> onNext, Expression<Action<Exception>> onError, Expression<Action> onCompleted)
  1640. {
  1641. if (source == null)
  1642. {
  1643. throw new ArgumentNullException(nameof(source));
  1644. }
  1645. if (onNext == null)
  1646. {
  1647. throw new ArgumentNullException(nameof(onNext));
  1648. }
  1649. if (onError == null)
  1650. {
  1651. throw new ArgumentNullException(nameof(onError));
  1652. }
  1653. if (onCompleted == null)
  1654. {
  1655. throw new ArgumentNullException(nameof(onCompleted));
  1656. }
  1657. return source.Provider.CreateQuery<TSource>(
  1658. Expression.Call(
  1659. null,
  1660. #if CRIPPLED_REFLECTION
  1661. InfoOf(() => QueryableEx.Do<TSource>(default, default, default, default)),
  1662. #else
  1663. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1664. #endif
  1665. source.Expression,
  1666. onNext,
  1667. onError,
  1668. onCompleted
  1669. )
  1670. );
  1671. }
  1672. #pragma warning disable 1591
  1673. [EditorBrowsable(EditorBrowsableState.Never)]
  1674. public static IEnumerable<TSource> Do<TSource>(IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
  1675. {
  1676. return EnumerableEx.Do(source, onNext, onError, onCompleted);
  1677. }
  1678. #pragma warning restore 1591
  1679. /// <summary>
  1680. /// Lazily invokes observer methods for each value in the sequence, and upon successful or exceptional termination.
  1681. /// </summary>
  1682. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1683. /// <param name="source">Source sequence.</param>
  1684. /// <param name="observer">Observer to invoke notification calls on.</param>
  1685. /// <returns>Sequence exhibiting the side-effects of observer method invocation upon enumeration.</returns>
  1686. public static IQueryable<TSource> Do<TSource>(this IQueryable<TSource> source, IObserver<TSource> observer)
  1687. {
  1688. if (source == null)
  1689. {
  1690. throw new ArgumentNullException(nameof(source));
  1691. }
  1692. if (observer == null)
  1693. {
  1694. throw new ArgumentNullException(nameof(observer));
  1695. }
  1696. return source.Provider.CreateQuery<TSource>(
  1697. Expression.Call(
  1698. null,
  1699. #if CRIPPLED_REFLECTION
  1700. InfoOf(() => QueryableEx.Do<TSource>(default, default(IObserver<TSource>))),
  1701. #else
  1702. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1703. #endif
  1704. source.Expression,
  1705. Expression.Constant(observer, typeof(IObserver<TSource>))
  1706. )
  1707. );
  1708. }
  1709. #pragma warning disable 1591
  1710. [EditorBrowsable(EditorBrowsableState.Never)]
  1711. public static IEnumerable<TSource> Do<TSource>(IEnumerable<TSource> source, IObserver<TSource> observer)
  1712. {
  1713. return EnumerableEx.Do(source, observer);
  1714. }
  1715. #pragma warning restore 1591
  1716. /// <summary>
  1717. /// Generates a sequence of non-overlapping adjacent buffers over the source sequence.
  1718. /// </summary>
  1719. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1720. /// <param name="source">Source sequence.</param>
  1721. /// <param name="count">Number of elements for allocated buffers.</param>
  1722. /// <returns>Sequence of buffers containing source sequence elements.</returns>
  1723. public static IQueryable<IList<TSource>> Buffer<TSource>(this IQueryable<TSource> source, int count)
  1724. {
  1725. if (source == null)
  1726. {
  1727. throw new ArgumentNullException(nameof(source));
  1728. }
  1729. return source.Provider.CreateQuery<IList<TSource>>(
  1730. Expression.Call(
  1731. null,
  1732. #if CRIPPLED_REFLECTION
  1733. InfoOf(() => QueryableEx.Buffer<TSource>(default, default)),
  1734. #else
  1735. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1736. #endif
  1737. source.Expression,
  1738. Expression.Constant(count, typeof(int))
  1739. )
  1740. );
  1741. }
  1742. #pragma warning disable 1591
  1743. [EditorBrowsable(EditorBrowsableState.Never)]
  1744. public static IEnumerable<IList<TSource>> Buffer<TSource>(IEnumerable<TSource> source, int count)
  1745. {
  1746. return EnumerableEx.Buffer(source, count);
  1747. }
  1748. #pragma warning restore 1591
  1749. /// <summary>
  1750. /// Generates a sequence of buffers over the source sequence, with specified length and possible overlap.
  1751. /// </summary>
  1752. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1753. /// <param name="source">Source sequence.</param>
  1754. /// <param name="count">Number of elements for allocated buffers.</param>
  1755. /// <param name="skip">Number of elements to skip between the start of consecutive buffers.</param>
  1756. /// <returns>Sequence of buffers containing source sequence elements.</returns>
  1757. public static IQueryable<IList<TSource>> Buffer<TSource>(this IQueryable<TSource> source, int count, int skip)
  1758. {
  1759. if (source == null)
  1760. {
  1761. throw new ArgumentNullException(nameof(source));
  1762. }
  1763. return source.Provider.CreateQuery<IList<TSource>>(
  1764. Expression.Call(
  1765. null,
  1766. #if CRIPPLED_REFLECTION
  1767. InfoOf(() => QueryableEx.Buffer<TSource>(default, default, default)),
  1768. #else
  1769. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1770. #endif
  1771. source.Expression,
  1772. Expression.Constant(count, typeof(int)),
  1773. Expression.Constant(skip, typeof(int))
  1774. )
  1775. );
  1776. }
  1777. #pragma warning disable 1591
  1778. [EditorBrowsable(EditorBrowsableState.Never)]
  1779. public static IEnumerable<IList<TSource>> Buffer<TSource>(IEnumerable<TSource> source, int count, int skip)
  1780. {
  1781. return EnumerableEx.Buffer(source, count, skip);
  1782. }
  1783. #pragma warning restore 1591
  1784. /// <summary>
  1785. /// Ignores all elements in the source sequence.
  1786. /// </summary>
  1787. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1788. /// <param name="source">Source sequence.</param>
  1789. /// <returns>Source sequence without its elements.</returns>
  1790. public static IQueryable<TSource> IgnoreElements<TSource>(this IQueryable<TSource> source)
  1791. {
  1792. if (source == null)
  1793. {
  1794. throw new ArgumentNullException(nameof(source));
  1795. }
  1796. return source.Provider.CreateQuery<TSource>(
  1797. Expression.Call(
  1798. null,
  1799. #if CRIPPLED_REFLECTION
  1800. InfoOf(() => QueryableEx.IgnoreElements<TSource>(default)),
  1801. #else
  1802. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1803. #endif
  1804. source.Expression
  1805. )
  1806. );
  1807. }
  1808. #pragma warning disable 1591
  1809. [EditorBrowsable(EditorBrowsableState.Never)]
  1810. public static IEnumerable<TSource> IgnoreElements<TSource>(IEnumerable<TSource> source)
  1811. {
  1812. return EnumerableEx.IgnoreElements(source);
  1813. }
  1814. #pragma warning restore 1591
  1815. /// <summary>
  1816. /// Returns elements with a distinct key value by using the default equality comparer to compare key values.
  1817. /// </summary>
  1818. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1819. /// <typeparam name="TKey">Key type.</typeparam>
  1820. /// <param name="source">Source sequence.</param>
  1821. /// <param name="keySelector">Key selector.</param>
  1822. /// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>
  1823. public static IQueryable<TSource> Distinct<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
  1824. {
  1825. if (source == null)
  1826. {
  1827. throw new ArgumentNullException(nameof(source));
  1828. }
  1829. if (keySelector == null)
  1830. {
  1831. throw new ArgumentNullException(nameof(keySelector));
  1832. }
  1833. return source.Provider.CreateQuery<TSource>(
  1834. Expression.Call(
  1835. null,
  1836. #if CRIPPLED_REFLECTION
  1837. InfoOf(() => QueryableEx.Distinct<TSource, TKey>(default, default)),
  1838. #else
  1839. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  1840. #endif
  1841. source.Expression,
  1842. keySelector
  1843. )
  1844. );
  1845. }
  1846. #pragma warning disable 1591
  1847. [EditorBrowsable(EditorBrowsableState.Never)]
  1848. public static IEnumerable<TSource> Distinct<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  1849. {
  1850. return EnumerableEx.Distinct(source, keySelector);
  1851. }
  1852. #pragma warning restore 1591
  1853. /// <summary>
  1854. /// Returns elements with a distinct key value by using the specified equality comparer to compare key values.
  1855. /// </summary>
  1856. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1857. /// <typeparam name="TKey">Key type.</typeparam>
  1858. /// <param name="source">Source sequence.</param>
  1859. /// <param name="keySelector">Key selector.</param>
  1860. /// <param name="comparer">Comparer used to compare key values.</param>
  1861. /// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>
  1862. public static IQueryable<TSource> Distinct<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IEqualityComparer<TKey> comparer)
  1863. {
  1864. if (source == null)
  1865. {
  1866. throw new ArgumentNullException(nameof(source));
  1867. }
  1868. if (keySelector == null)
  1869. {
  1870. throw new ArgumentNullException(nameof(keySelector));
  1871. }
  1872. if (comparer == null)
  1873. {
  1874. throw new ArgumentNullException(nameof(comparer));
  1875. }
  1876. return source.Provider.CreateQuery<TSource>(
  1877. Expression.Call(
  1878. null,
  1879. #if CRIPPLED_REFLECTION
  1880. InfoOf(() => QueryableEx.Distinct<TSource, TKey>(default, default, default)),
  1881. #else
  1882. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  1883. #endif
  1884. source.Expression,
  1885. keySelector,
  1886. Expression.Constant(comparer, typeof(IEqualityComparer<TKey>))
  1887. )
  1888. );
  1889. }
  1890. #pragma warning disable 1591
  1891. [EditorBrowsable(EditorBrowsableState.Never)]
  1892. public static IEnumerable<TSource> Distinct<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  1893. {
  1894. return EnumerableEx.Distinct(source, keySelector, comparer);
  1895. }
  1896. #pragma warning restore 1591
  1897. /// <summary>
  1898. /// Returns consecutive distinct elements by using the default equality comparer to compare values.
  1899. /// </summary>
  1900. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1901. /// <param name="source">Source sequence.</param>
  1902. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  1903. public static IQueryable<TSource> DistinctUntilChanged<TSource>(this IQueryable<TSource> source)
  1904. {
  1905. if (source == null)
  1906. {
  1907. throw new ArgumentNullException(nameof(source));
  1908. }
  1909. return source.Provider.CreateQuery<TSource>(
  1910. Expression.Call(
  1911. null,
  1912. #if CRIPPLED_REFLECTION
  1913. InfoOf(() => QueryableEx.DistinctUntilChanged<TSource>(default)),
  1914. #else
  1915. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1916. #endif
  1917. source.Expression
  1918. )
  1919. );
  1920. }
  1921. #pragma warning disable 1591
  1922. [EditorBrowsable(EditorBrowsableState.Never)]
  1923. public static IEnumerable<TSource> DistinctUntilChanged<TSource>(IEnumerable<TSource> source)
  1924. {
  1925. return EnumerableEx.DistinctUntilChanged(source);
  1926. }
  1927. #pragma warning restore 1591
  1928. /// <summary>
  1929. /// Returns consecutive distinct elements by using the specified equality comparer to compare values.
  1930. /// </summary>
  1931. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1932. /// <param name="source">Source sequence.</param>
  1933. /// <param name="comparer">Comparer used to compare values.</param>
  1934. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  1935. public static IQueryable<TSource> DistinctUntilChanged<TSource>(this IQueryable<TSource> source, IEqualityComparer<TSource> comparer)
  1936. {
  1937. if (source == null)
  1938. {
  1939. throw new ArgumentNullException(nameof(source));
  1940. }
  1941. if (comparer == null)
  1942. {
  1943. throw new ArgumentNullException(nameof(comparer));
  1944. }
  1945. return source.Provider.CreateQuery<TSource>(
  1946. Expression.Call(
  1947. null,
  1948. #if CRIPPLED_REFLECTION
  1949. InfoOf(() => QueryableEx.DistinctUntilChanged<TSource>(default, default)),
  1950. #else
  1951. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  1952. #endif
  1953. source.Expression,
  1954. Expression.Constant(comparer, typeof(IEqualityComparer<TSource>))
  1955. )
  1956. );
  1957. }
  1958. #pragma warning disable 1591
  1959. [EditorBrowsable(EditorBrowsableState.Never)]
  1960. public static IEnumerable<TSource> DistinctUntilChanged<TSource>(IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  1961. {
  1962. return EnumerableEx.DistinctUntilChanged(source, comparer);
  1963. }
  1964. #pragma warning restore 1591
  1965. /// <summary>
  1966. /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
  1967. /// </summary>
  1968. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  1969. /// <typeparam name="TKey">Key type.</typeparam>
  1970. /// <param name="source">Source sequence.</param>
  1971. /// <param name="keySelector">Key selector.</param>
  1972. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  1973. public static IQueryable<TSource> DistinctUntilChanged<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
  1974. {
  1975. if (source == null)
  1976. {
  1977. throw new ArgumentNullException(nameof(source));
  1978. }
  1979. if (keySelector == null)
  1980. {
  1981. throw new ArgumentNullException(nameof(keySelector));
  1982. }
  1983. return source.Provider.CreateQuery<TSource>(
  1984. Expression.Call(
  1985. null,
  1986. #if CRIPPLED_REFLECTION
  1987. InfoOf(() => QueryableEx.DistinctUntilChanged<TSource, TKey>(default, default)),
  1988. #else
  1989. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  1990. #endif
  1991. source.Expression,
  1992. keySelector
  1993. )
  1994. );
  1995. }
  1996. #pragma warning disable 1591
  1997. [EditorBrowsable(EditorBrowsableState.Never)]
  1998. public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  1999. {
  2000. return EnumerableEx.DistinctUntilChanged(source, keySelector);
  2001. }
  2002. #pragma warning restore 1591
  2003. /// <summary>
  2004. /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
  2005. /// </summary>
  2006. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2007. /// <typeparam name="TKey">Key type.</typeparam>
  2008. /// <param name="source">Source sequence.</param>
  2009. /// <param name="keySelector">Key selector.</param>
  2010. /// <param name="comparer">Comparer used to compare key values.</param>
  2011. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  2012. public static IQueryable<TSource> DistinctUntilChanged<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IEqualityComparer<TKey> comparer)
  2013. {
  2014. if (source == null)
  2015. {
  2016. throw new ArgumentNullException(nameof(source));
  2017. }
  2018. if (keySelector == null)
  2019. {
  2020. throw new ArgumentNullException(nameof(keySelector));
  2021. }
  2022. if (comparer == null)
  2023. {
  2024. throw new ArgumentNullException(nameof(comparer));
  2025. }
  2026. return source.Provider.CreateQuery<TSource>(
  2027. Expression.Call(
  2028. null,
  2029. #if CRIPPLED_REFLECTION
  2030. InfoOf(() => QueryableEx.DistinctUntilChanged<TSource, TKey>(default, default, default)),
  2031. #else
  2032. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
  2033. #endif
  2034. source.Expression,
  2035. keySelector,
  2036. Expression.Constant(comparer, typeof(IEqualityComparer<TKey>))
  2037. )
  2038. );
  2039. }
  2040. #pragma warning disable 1591
  2041. [EditorBrowsable(EditorBrowsableState.Never)]
  2042. public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  2043. {
  2044. return EnumerableEx.DistinctUntilChanged(source, keySelector, comparer);
  2045. }
  2046. #pragma warning restore 1591
  2047. /// <summary>
  2048. /// Expands the sequence by recursively applying a selector function.
  2049. /// </summary>
  2050. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2051. /// <param name="source">Source sequence.</param>
  2052. /// <param name="selector">Selector function to retrieve the next sequence to expand.</param>
  2053. /// <returns>Sequence with results from the recursive expansion of the source sequence.</returns>
  2054. public static IQueryable<TSource> Expand<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, IEnumerable<TSource>>> selector)
  2055. {
  2056. if (source == null)
  2057. {
  2058. throw new ArgumentNullException(nameof(source));
  2059. }
  2060. if (selector == null)
  2061. {
  2062. throw new ArgumentNullException(nameof(selector));
  2063. }
  2064. return source.Provider.CreateQuery<TSource>(
  2065. Expression.Call(
  2066. null,
  2067. #if CRIPPLED_REFLECTION
  2068. InfoOf(() => QueryableEx.Expand<TSource>(default, default)),
  2069. #else
  2070. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2071. #endif
  2072. source.Expression,
  2073. selector
  2074. )
  2075. );
  2076. }
  2077. #pragma warning disable 1591
  2078. [EditorBrowsable(EditorBrowsableState.Never)]
  2079. public static IEnumerable<TSource> Expand<TSource>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> selector)
  2080. {
  2081. return EnumerableEx.Expand(source, selector);
  2082. }
  2083. #pragma warning restore 1591
  2084. /// <summary>
  2085. /// Returns the source sequence prefixed with the specified value.
  2086. /// </summary>
  2087. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2088. /// <param name="source">Source sequence.</param>
  2089. /// <param name="values">Values to prefix the sequence with.</param>
  2090. /// <returns>Sequence starting with the specified prefix value, followed by the source sequence.</returns>
  2091. public static IQueryable<TSource> StartWith<TSource>(this IQueryable<TSource> source, params TSource[] values)
  2092. {
  2093. if (source == null)
  2094. {
  2095. throw new ArgumentNullException(nameof(source));
  2096. }
  2097. return source.Provider.CreateQuery<TSource>(
  2098. Expression.Call(
  2099. null,
  2100. #if CRIPPLED_REFLECTION
  2101. InfoOf(() => QueryableEx.StartWith<TSource>(default, default)),
  2102. #else
  2103. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2104. #endif
  2105. source.Expression,
  2106. Expression.Constant(values, typeof(TSource[]))
  2107. )
  2108. );
  2109. }
  2110. #pragma warning disable 1591
  2111. [EditorBrowsable(EditorBrowsableState.Never)]
  2112. public static IEnumerable<TSource> StartWith<TSource>(IEnumerable<TSource> source, params TSource[] values)
  2113. {
  2114. return EnumerableEx.StartWith(source, values);
  2115. }
  2116. #pragma warning restore 1591
  2117. /// <summary>
  2118. /// Generates a sequence of accumulated values by scanning the source sequence and applying an accumulator function.
  2119. /// </summary>
  2120. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2121. /// <typeparam name="TAccumulate">Accumulation type.</typeparam>
  2122. /// <param name="source">Source sequence.</param>
  2123. /// <param name="seed">Accumulator seed value.</param>
  2124. /// <param name="accumulator">Accumulation function to apply to the current accumulation value and each element of the sequence.</param>
  2125. /// <returns>Sequence with all intermediate accumulation values resulting from scanning the sequence.</returns>
  2126. public static IQueryable<TAccumulate> Scan<TSource, TAccumulate>(this IQueryable<TSource> source, TAccumulate seed, Expression<Func<TAccumulate, TSource, TAccumulate>> accumulator)
  2127. {
  2128. if (source == null)
  2129. {
  2130. throw new ArgumentNullException(nameof(source));
  2131. }
  2132. if (accumulator == null)
  2133. {
  2134. throw new ArgumentNullException(nameof(accumulator));
  2135. }
  2136. return source.Provider.CreateQuery<TAccumulate>(
  2137. Expression.Call(
  2138. null,
  2139. #if CRIPPLED_REFLECTION
  2140. InfoOf(() => QueryableEx.Scan<TSource, TAccumulate>(default, default, default)),
  2141. #else
  2142. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TAccumulate)),
  2143. #endif
  2144. source.Expression,
  2145. Expression.Constant(seed, typeof(TAccumulate)),
  2146. accumulator
  2147. )
  2148. );
  2149. }
  2150. #pragma warning disable 1591
  2151. [EditorBrowsable(EditorBrowsableState.Never)]
  2152. public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>(IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator)
  2153. {
  2154. return EnumerableEx.Scan(source, seed, accumulator);
  2155. }
  2156. #pragma warning restore 1591
  2157. /// <summary>
  2158. /// Generates a sequence of accumulated values by scanning the source sequence and applying an accumulator function.
  2159. /// </summary>
  2160. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2161. /// <param name="source">Source sequence.</param>
  2162. /// <param name="accumulator">Accumulation function to apply to the current accumulation value and each element of the sequence.</param>
  2163. /// <returns>Sequence with all intermediate accumulation values resulting from scanning the sequence.</returns>
  2164. public static IQueryable<TSource> Scan<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, TSource, TSource>> accumulator)
  2165. {
  2166. if (source == null)
  2167. {
  2168. throw new ArgumentNullException(nameof(source));
  2169. }
  2170. if (accumulator == null)
  2171. {
  2172. throw new ArgumentNullException(nameof(accumulator));
  2173. }
  2174. return source.Provider.CreateQuery<TSource>(
  2175. Expression.Call(
  2176. null,
  2177. #if CRIPPLED_REFLECTION
  2178. InfoOf(() => QueryableEx.Scan<TSource>(default, default)),
  2179. #else
  2180. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2181. #endif
  2182. source.Expression,
  2183. accumulator
  2184. )
  2185. );
  2186. }
  2187. #pragma warning disable 1591
  2188. [EditorBrowsable(EditorBrowsableState.Never)]
  2189. public static IEnumerable<TSource> Scan<TSource>(IEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator)
  2190. {
  2191. return EnumerableEx.Scan(source, accumulator);
  2192. }
  2193. #pragma warning restore 1591
  2194. #if !(REFERENCE_ASSEMBLY && (NETCOREAPP2_0 || NETSTANDARD2_1))
  2195. /// <summary>
  2196. /// Returns a specified number of contiguous elements from the end of the sequence.
  2197. /// </summary>
  2198. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2199. /// <param name="source">Source sequence.</param>
  2200. /// <param name="count">The number of elements to take from the end of the sequence.</param>
  2201. /// <returns>Sequence with the specified number of elements counting from the end of the source sequence.</returns>
  2202. public static IQueryable<TSource> TakeLast<TSource>(this IQueryable<TSource> source, int count)
  2203. {
  2204. if (source == null)
  2205. {
  2206. throw new ArgumentNullException(nameof(source));
  2207. }
  2208. return source.Provider.CreateQuery<TSource>(
  2209. Expression.Call(
  2210. null,
  2211. #if CRIPPLED_REFLECTION
  2212. InfoOf(() => QueryableEx.TakeLast<TSource>(default, default)),
  2213. #else
  2214. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2215. #endif
  2216. source.Expression,
  2217. Expression.Constant(count, typeof(int))
  2218. )
  2219. );
  2220. }
  2221. #pragma warning disable 1591
  2222. [EditorBrowsable(EditorBrowsableState.Never)]
  2223. public static IEnumerable<TSource> TakeLast<TSource>(IEnumerable<TSource> source, int count)
  2224. {
  2225. return EnumerableEx.TakeLast(source, count);
  2226. }
  2227. #pragma warning restore 1591
  2228. /// <summary>
  2229. /// Bypasses a specified number of contiguous elements from the end of the sequence and returns the remaining elements.
  2230. /// </summary>
  2231. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2232. /// <param name="source">Source sequence.</param>
  2233. /// <param name="count">The number of elements to skip from the end of the sequence before returning the remaining elements.</param>
  2234. /// <returns>Sequence bypassing the specified number of elements counting from the end of the source sequence.</returns>
  2235. public static IQueryable<TSource> SkipLast<TSource>(this IQueryable<TSource> source, int count)
  2236. {
  2237. if (source == null)
  2238. {
  2239. throw new ArgumentNullException(nameof(source));
  2240. }
  2241. return source.Provider.CreateQuery<TSource>(
  2242. Expression.Call(
  2243. null,
  2244. #if CRIPPLED_REFLECTION
  2245. InfoOf(() => QueryableEx.SkipLast<TSource>(default, default)),
  2246. #else
  2247. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2248. #endif
  2249. source.Expression,
  2250. Expression.Constant(count, typeof(int))
  2251. )
  2252. );
  2253. }
  2254. #pragma warning disable 1591
  2255. [EditorBrowsable(EditorBrowsableState.Never)]
  2256. public static IEnumerable<TSource> SkipLast<TSource>(IEnumerable<TSource> source, int count)
  2257. {
  2258. return EnumerableEx.SkipLast(source, count);
  2259. }
  2260. #pragma warning restore 1591
  2261. #endif
  2262. /// <summary>
  2263. /// Repeats and concatenates the source sequence infinitely.
  2264. /// </summary>
  2265. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2266. /// <param name="source">Source sequence.</param>
  2267. /// <returns>Sequence obtained by concatenating the source sequence to itself infinitely.</returns>
  2268. public static IQueryable<TSource> Repeat<TSource>(this IQueryable<TSource> source)
  2269. {
  2270. if (source == null)
  2271. {
  2272. throw new ArgumentNullException(nameof(source));
  2273. }
  2274. return source.Provider.CreateQuery<TSource>(
  2275. Expression.Call(
  2276. null,
  2277. #if CRIPPLED_REFLECTION
  2278. InfoOf(() => QueryableEx.Repeat<TSource>(default(IQueryable<TSource>))),
  2279. #else
  2280. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2281. #endif
  2282. source.Expression
  2283. )
  2284. );
  2285. }
  2286. #pragma warning disable 1591
  2287. [EditorBrowsable(EditorBrowsableState.Never)]
  2288. public static IEnumerable<TSource> Repeat<TSource>(IEnumerable<TSource> source)
  2289. {
  2290. return EnumerableEx.Repeat(source);
  2291. }
  2292. #pragma warning restore 1591
  2293. /// <summary>
  2294. /// Repeats and concatenates the source sequence the given number of times.
  2295. /// </summary>
  2296. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  2297. /// <param name="source">Source sequence.</param>
  2298. /// <param name="count">Number of times to repeat the source sequence.</param>
  2299. /// <returns>Sequence obtained by concatenating the source sequence to itself the specified number of times.</returns>
  2300. public static IQueryable<TSource> Repeat<TSource>(this IQueryable<TSource> source, int count)
  2301. {
  2302. if (source == null)
  2303. {
  2304. throw new ArgumentNullException(nameof(source));
  2305. }
  2306. return source.Provider.CreateQuery<TSource>(
  2307. Expression.Call(
  2308. null,
  2309. #if CRIPPLED_REFLECTION
  2310. InfoOf(() => QueryableEx.Repeat<TSource>(default(IQueryable<TSource>), default)),
  2311. #else
  2312. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
  2313. #endif
  2314. source.Expression,
  2315. Expression.Constant(count, typeof(int))
  2316. )
  2317. );
  2318. }
  2319. #pragma warning disable 1591
  2320. [EditorBrowsable(EditorBrowsableState.Never)]
  2321. public static IEnumerable<TSource> Repeat<TSource>(IEnumerable<TSource> source, int count)
  2322. {
  2323. return EnumerableEx.Repeat(source, count);
  2324. }
  2325. #pragma warning restore 1591
  2326. /// <summary>
  2327. /// Returns a sequence with no elements.
  2328. /// </summary>
  2329. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  2330. /// <param name="provider">Query provider.</param>
  2331. /// <returns>Sequence with no elements.</returns>
  2332. public static IQueryable<TResult> Empty<TResult>(this IQueryProvider provider)
  2333. {
  2334. if (provider == null)
  2335. {
  2336. throw new ArgumentNullException(nameof(provider));
  2337. }
  2338. return provider.CreateQuery<TResult>(
  2339. Expression.Call(
  2340. null,
  2341. #if CRIPPLED_REFLECTION
  2342. InfoOf(() => QueryableEx.Empty<TResult>(default)),
  2343. #else
  2344. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  2345. #endif
  2346. Expression.Constant(provider, typeof(IQueryProvider))
  2347. )
  2348. );
  2349. }
  2350. #pragma warning disable 1591
  2351. [EditorBrowsable(EditorBrowsableState.Never)]
  2352. public static /*!*/IQueryable<TResult> Empty<TResult>()
  2353. {
  2354. return Enumerable.Empty<TResult>().AsQueryable();
  2355. }
  2356. #pragma warning restore 1591
  2357. /// <summary>
  2358. /// Generates a sequence of integral numbers within a specified range.
  2359. /// </summary>
  2360. /// <param name="provider">Query provider.</param>
  2361. /// <param name="start">The value of the first integer in the sequence.</param>
  2362. /// <param name="count">The number of sequential integers to generate.</param>
  2363. /// <returns>Sequence that contains a range of sequential integral numbers.</returns>
  2364. public static IQueryable<int> Range(this IQueryProvider provider, int start, int count)
  2365. {
  2366. if (provider == null)
  2367. {
  2368. throw new ArgumentNullException(nameof(provider));
  2369. }
  2370. return provider.CreateQuery<int>(
  2371. Expression.Call(
  2372. null,
  2373. #if CRIPPLED_REFLECTION
  2374. InfoOf(() => QueryableEx.Range(default, default, default)),
  2375. #else
  2376. (MethodInfo)MethodInfo.GetCurrentMethod(),
  2377. #endif
  2378. Expression.Constant(provider, typeof(IQueryProvider)),
  2379. Expression.Constant(start, typeof(int)),
  2380. Expression.Constant(count, typeof(int))
  2381. )
  2382. );
  2383. }
  2384. #pragma warning disable 1591
  2385. [EditorBrowsable(EditorBrowsableState.Never)]
  2386. public static /*!*/IQueryable<int> Range(int start, int count)
  2387. {
  2388. return Enumerable.Range(start, count).AsQueryable();
  2389. }
  2390. #pragma warning restore 1591
  2391. /// <summary>
  2392. /// Generates a sequence that contains one repeated value.
  2393. /// </summary>
  2394. /// <typeparam name="TResult">Result sequence element type.</typeparam>
  2395. /// <param name="provider">Query provider.</param>
  2396. /// <param name="element">The value to be repeated.</param>
  2397. /// <param name="count">The number of times to repeat the value in the generated sequence.</param>
  2398. /// <returns>Sequence that contains a repeated value.</returns>
  2399. public static IQueryable<TResult> Repeat<TResult>(this IQueryProvider provider, TResult element, int count)
  2400. {
  2401. if (provider == null)
  2402. {
  2403. throw new ArgumentNullException(nameof(provider));
  2404. }
  2405. return provider.CreateQuery<TResult>(
  2406. Expression.Call(
  2407. null,
  2408. #if CRIPPLED_REFLECTION
  2409. InfoOf(() => QueryableEx.Repeat<TResult>(default, default, default)),
  2410. #else
  2411. ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
  2412. #endif
  2413. Expression.Constant(provider, typeof(IQueryProvider)),
  2414. Expression.Constant(element, typeof(TResult)),
  2415. Expression.Constant(count, typeof(int))
  2416. )
  2417. );
  2418. }
  2419. #pragma warning disable 1591
  2420. [EditorBrowsable(EditorBrowsableState.Never)]
  2421. public static /*!*/IQueryable<TResult> Repeat<TResult>(TResult element, int count)
  2422. {
  2423. return EnumerableEx.Repeat<TResult>(element, count).AsQueryable();
  2424. }
  2425. #pragma warning restore 1591
  2426. /// <summary>
  2427. /// Gets the local Queryable provider.
  2428. /// </summary>
  2429. public static IQueryProvider Provider
  2430. {
  2431. get
  2432. {
  2433. return new QueryProviderShim();
  2434. }
  2435. }
  2436. private class QueryProviderShim : IQueryProvider
  2437. {
  2438. public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
  2439. {
  2440. var provider = new TElement[0].AsQueryable().Provider;
  2441. var res = Redir(expression);
  2442. return provider.CreateQuery<TElement>(res);
  2443. }
  2444. public IQueryable CreateQuery(Expression expression)
  2445. {
  2446. return CreateQuery<object>(expression);
  2447. }
  2448. public TResult Execute<TResult>(Expression expression)
  2449. {
  2450. var provider = new TResult[0].AsQueryable().Provider;
  2451. var res = Redir(expression);
  2452. return provider.Execute<TResult>(res);
  2453. }
  2454. public object Execute(Expression expression)
  2455. {
  2456. return Execute<object>(expression);
  2457. }
  2458. private static Expression Redir(Expression expression)
  2459. {
  2460. if (expression is MethodCallExpression mce && mce.Method.DeclaringType == typeof(QueryableEx))
  2461. {
  2462. if (mce.Arguments.Count >= 1 && typeof(IQueryProvider).IsAssignableFrom(mce.Arguments[0].Type))
  2463. {
  2464. if (mce.Arguments[0] is ConstantExpression ce)
  2465. {
  2466. if (ce.Value is QueryProviderShim)
  2467. {
  2468. var targetType = typeof(QueryableEx);
  2469. var method = mce.Method;
  2470. var methods = GetMethods(targetType);
  2471. var arguments = mce.Arguments.Skip(1).ToList();
  2472. //
  2473. // From all the operators with the method's name, find the one that matches all arguments.
  2474. //
  2475. var typeArgs = method.IsGenericMethod ? method.GetGenericArguments() : null;
  2476. var targetMethod = methods[method.Name].FirstOrDefault(candidateMethod => ArgsMatch(candidateMethod, arguments, typeArgs));
  2477. if (targetMethod == null)
  2478. {
  2479. throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "There is no method '{0}' on type '{1}' that matches the specified arguments", method.Name, targetType.Name));
  2480. }
  2481. //
  2482. // Restore generic arguments.
  2483. //
  2484. if (typeArgs != null)
  2485. {
  2486. targetMethod = targetMethod.MakeGenericMethod(typeArgs);
  2487. }
  2488. //
  2489. // Finally, we need to deal with mismatches on Expression<Func<...>> versus Func<...>.
  2490. //
  2491. var parameters = targetMethod.GetParameters();
  2492. for (int i = 0, n = parameters.Length; i < n; i++)
  2493. {
  2494. arguments[i] = Unquote(arguments[i]);
  2495. }
  2496. //
  2497. // Emit a new call to the discovered target method.
  2498. //
  2499. return Expression.Call(null, targetMethod, arguments);
  2500. }
  2501. }
  2502. }
  2503. }
  2504. return expression;
  2505. }
  2506. private static ILookup<string, MethodInfo> GetMethods(Type type)
  2507. {
  2508. return type.GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name);
  2509. }
  2510. private static bool ArgsMatch(MethodInfo method, IList<Expression> arguments, Type[] typeArgs)
  2511. {
  2512. //
  2513. // Number of parameters should match. Notice we've sanitized IQueryProvider "this"
  2514. // parameters first (see Redir).
  2515. //
  2516. var parameters = method.GetParameters();
  2517. if (parameters.Length != arguments.Count)
  2518. {
  2519. return false;
  2520. }
  2521. //
  2522. // Genericity should match too.
  2523. //
  2524. if (!method.IsGenericMethod && typeArgs != null && typeArgs.Length > 0)
  2525. {
  2526. return false;
  2527. }
  2528. //
  2529. // Reconstruct the generic method if needed.
  2530. //
  2531. if (method.IsGenericMethodDefinition)
  2532. {
  2533. if (typeArgs == null)
  2534. {
  2535. return false;
  2536. }
  2537. if (method.GetGenericArguments().Length != typeArgs.Length)
  2538. {
  2539. return false;
  2540. }
  2541. var result = method.MakeGenericMethod(typeArgs);
  2542. parameters = result.GetParameters();
  2543. }
  2544. //
  2545. // Check compatibility for the parameter types.
  2546. //
  2547. for (int i = 0, n = arguments.Count; i < n; i++)
  2548. {
  2549. var parameterType = parameters[i].ParameterType;
  2550. var argument = arguments[i];
  2551. //
  2552. // For operators that take a function (like Where, Select), we'll be faced
  2553. // with a quoted argument and a discrepancy between Expression<Func<...>>
  2554. // and the underlying Func<...>.
  2555. //
  2556. if (!parameterType.IsAssignableFrom(argument.Type))
  2557. {
  2558. argument = Unquote(argument);
  2559. if (!parameterType.IsAssignableFrom(argument.Type))
  2560. {
  2561. return false;
  2562. }
  2563. }
  2564. }
  2565. return true;
  2566. }
  2567. private static Expression Unquote(Expression expression)
  2568. {
  2569. //
  2570. // Get rid of all outer quotes around an expression.
  2571. //
  2572. while (expression.NodeType == ExpressionType.Quote)
  2573. {
  2574. expression = ((UnaryExpression)expression).Operand;
  2575. }
  2576. return expression;
  2577. }
  2578. }
  2579. internal static Expression GetSourceExpression<TSource>(IEnumerable<TSource> source)
  2580. {
  2581. if (source is IQueryable<TSource> q)
  2582. {
  2583. return q.Expression;
  2584. }
  2585. return Expression.Constant(source, typeof(IEnumerable<TSource>));
  2586. }
  2587. internal static Expression GetSourceExpression<TSource>(IEnumerable<TSource>[] sources)
  2588. {
  2589. return Expression.NewArrayInit(
  2590. typeof(IEnumerable<TSource>),
  2591. sources.Select(source => GetSourceExpression(source))
  2592. );
  2593. }
  2594. internal static MethodInfo InfoOf<R>(Expression<Func<R>> f)
  2595. {
  2596. return ((MethodCallExpression)f.Body).Method;
  2597. }
  2598. }
  2599. }