From 9d1dc88952eb37109de1af003d5faa0e58073367 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Mon, 12 Sep 2022 20:46:33 +0200 Subject: [PATCH 001/214] Use PackageIcon + upgrade JetBrains.Annotations (#627) --- System.Linq.Dynamic.Core.sln | 4 +- resources/logo.ico | Bin 0 -> 36230 bytes resources/logo.png | Bin 0 -> 6548 bytes .../BlazorWASMExample.csproj | 2 +- .../ConsoleApp_net40_sqlite_original.csproj | 4 +- .../packages.config | 2 +- src/Directory.Build.props | 26 +++++++++++++ .../EntityFramework.DynamicLinq.csproj | 35 +++++------------- ...tyFrameworkCore.DynamicLinq.EFCore2.csproj | 32 +++------------- ...tyFrameworkCore.DynamicLinq.EFCore3.csproj | 29 +++------------ ...tyFrameworkCore.DynamicLinq.EFCore5.csproj | 29 +++------------ ...tyFrameworkCore.DynamicLinq.EFCore6.csproj | 29 +++------------ .../System.Linq.Dynamic.Core.csproj | 28 +++----------- ...EntityFramework.Classic.DynamicLinq.csproj | 32 +++------------- ...System.Linq.Dynamic.Core.Tests.Net5.csproj | 5 --- ...System.Linq.Dynamic.Core.Tests.Net6.csproj | 14 +++---- version.xml | 2 +- 17 files changed, 84 insertions(+), 189 deletions(-) create mode 100644 resources/logo.ico create mode 100644 resources/logo.png create mode 100644 src/Directory.Build.props diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln index 5f573c27..5f3c9303 100644 --- a/System.Linq.Dynamic.Core.sln +++ b/System.Linq.Dynamic.Core.sln @@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8463ED7E-69FB-49AE-85CF-0791AFD98E38}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DBD7D9B6-FCC7-4650-91AF-E6457573A68F}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{25E69107-C89E-4807-AA31-C49423F0F1E3}" ProjectSection(SolutionItems) = preProject @@ -19,7 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NuGet.txt = NuGet.txt README.md = README.md report\run-coverlet-local.cmd = report\run-coverlet-local.cmd - version.xml = version.xml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFramework.DynamicLinq.Tests.net452", "test\EntityFramework.DynamicLinq.Tests.net452\EntityFramework.DynamicLinq.Tests.net452.csproj", "{6B45E89C-0788-4942-924F-EF6397114BD1}" diff --git a/resources/logo.ico b/resources/logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..132e78359b8ebcf3b7337a4457f5eed79fa6fbba GIT binary patch literal 36230 zcmeHQ2Ur!?wjO$~=g_OtYzQ_)5J6N>5k*0&*i;p18z&%gTvTJKW2pTB}j*g1!X(objFeylL%csp z5UlYWe{ZC|Ah>@a2o3N}WFbrh@qO)~)qqw5S`BD5pw)m@16mDeHK5giRs(;Z2Hf3` z)sxANB-z^^neFPDlj`oCbIQ~-^SU5p+%+;fcv~*d%xl%^Xm;PeXV-l6(Vw5}+gA{A z_il;B-^bzW&*|fjuNc4kZhk*s-{UE|x>=6|A(I5*ASeTru0#iLz7Mnqv>UWbOnrS1 z=8hTj$IN5L9<_Y^-2Js*jEFef+u8Z(F@?-5wUs-NRb}o0R>}!%e70>Pju@1I@Hj$m( z&Vu>#^FJgao!7-Lf5+3+HO^ip3whOV)~k0sE-C5attL%QfL}>YNoMIYCcw9mO)n z!DmBM*Ieg1hqHE6(k;E+LMNO^geI1=l9gOLz6|zhH8_U0!0t0gh<)R{a)yoqn9)bTeWMjj1pXKCw zu3F|SyHw_q+`r)7&!C?`OQ6ro18d^Brr(W>jrC+khMB=ln$U*z8$Pb?dC1?d!j_R_ zm-==d&v(-gKU}XWu!cLixlbuM`3yNYa2sG*S!U%jUyW-?c9wf3h-F^^T11T+ZOAPw zEVZnT=i2;cZ)@8ROUN|t!%@uXcy;gS=p3{J z`t>53H0dlkI&vG}GG@7%xUNfO&a$)I%Rx&)OF-Y#ym@CvtK+vW_e^m(nwgz3)e&gN zmMzTWXR7b(=w!T6A-k&F$~N3~`sSNU>IJRg?)B@1^uY%?WMaayv#hFRz6|$R_Qjw@ zpzq1Y=hrJwo|IUr@>|zyC%Jrx8R|d-H#fR+`7(1lrQ#d=bYZ(6P}uL)$<8+X4svzf zM+F5XHAt)Z=VQn2Q@?&}GjLgRIdjUg^SLDZLY)5ynnP>XUK~`x>&u;);BdCEI0Yk< z5@WkzEED^&Mf^1bgLF^y@1?b~W4KRCp>gB>&@5mre@RKXO3j+_IQRpI%bQ7(o9}%O z`WCj~*56-F>dJ39%4~<*>gtjnbTDW7bcxGl@$qNJD(n~T<0RWvoh?&g$Jp5HB-m=w zH(ok@^r(c!j5$PxhAjJh5SKa2&FAw#v&qS6@y$DT3gHcVwF6ba*xAbRIJW~!0|VN+ zX_LrzZf+55j-$wnZ8nyhiR-#18;-~J4K!iG`D*1ZDJel;`LNn&q#q9+yhW{Au`Tc| zh~;Mb4m6u|bY{_>Jy%0tO?t)Kj&ga7+(4g~%W`u$ zOR`I4F4-}X4Y!fx@~w2^hUPj@SXhX*7E5oB7(si}(x|w&SQ1xl`uK4P4IRq)&jPU? zW|yU3)A;cjgI|aI{0$ddn{}v6#A9Ma>((#s+__V3)TE}~qo5$RW!X+=nI-#Gl3Uqs zUrqn`$1%0CNH>3+%Vj7K*SXgI{`8+uKcy4Lk4rzRP3O%!f%O5FeL83+Xa-qX&8f8w zTa%t_tgZYUOpG64P$6{u6x*>Q6+V4h&I{Xk^X6S5XJ;-8?w?p@$$sT)$#z|fcDt5N zovN4{m4Bq{gzG?PKvTjbl#I*rvo$iLZpic3l`H9~QohRX?%jJ8^GxmozW}iwz64Es zrzY8I`@6GTKH64Kmn0nw8_*xN?K5Q-=<3xX^i5~T)|Tr5w@tR)q`8`8x38qZgR?5V zr+TsO*Hr|UK3T#3um)iPP}B$Oq!sMaIp2Ikw{G54eT`0@yhFae3y|kz5X=9?J?NlL zb2&}=Fg7vKbG5bE!tyg;Tn`2{Z5<~gj~U%+dD z^mvt&`@s&agG3#${1S2AQl0Q|aiPf*CsxtJ<;#!I9@!?E1eyk#vRIQ$b-j;v;Nxg& za!=F&cwyV1f3IHjNJF1}_ii!Go_zuRG}{1dx3UfQ6KDwy7?55?Zsi*r)~u;i2P7Rx zDJHvO{tZ1n=!fsVBW^d+aqZe;^7rSqFab3AxgdNVURPN)J?|)&CCT*lo^yZ5yl_2; z3~56b&TAgqof{&i;Ti5P%wemI#hmT&KVMyXK`=Kr zm-)K5++-cNSzD2-r3E=#m_r|C1Uo_G*HbQ|`Ln;R)GyUVZt2_pxU4piUXj_N^Pteuj(HFRQS zN%m+9TpuG_x2BYh8zpgGD&4bd7n$qpk)={y*VG=+H)*Xh3#o8woL8>A>E-FC{;} zl!S4X`&mtL^L;FQk&Crej)|!$rYn^Xd}8+a@!SsHKO+cZ(Otg!(Y#6HwJjSqq(EOE z3h?$K|N8Z)F~;MDSTj-9M?E_^*`YqTp>7QA*N?b7>w08oW|9@=VJxF29dOw@$ZWAD zss1P|Ecvc!Q=T7;idFwa-R|1S<$mEoK@WpruLt=zp;nC>QHur*sF|-X^x<8h4|jKJ zfbr2A^GB?!ksJDrgqRr7o`3K_^ISkxN5lH{)mR6(-J|UH7#SI3nx^^4$jD!4WR#qt z`H8yy641EuC!N}cQoB~ID6B;b3T+lhZJ>|V&_~Ng%KG5?QD3Yd4cuJG-NuHT(Qifs zwW66{eo23vJEtmcmFr_UIb@G9hwT9yjJY-#Z@4b7><-38MKT+kpqjYfu;G+m{rX?- zKwsFgre|yOyRoscVMN=uTe?O@Qm3%C6d4*q?Sq3U9CEd7*^)w=H-kO`#JQ|kKN_Nb z`1w+xkD`9~I5~;+f!od-Xd67oyLm&iUHHkrKP0w&xqsz;h3hC_#Z??O@^TcA(C%;mY++DVt?Ay%S#+rxzC71yW)EBvP+u ze*Ix};p^{yHlS(K{z?7&pL=WAFnS|tASI!18i^`i&HW4*H{*N-k;C^lNE zACc5KB7&k&KRQAmJim@a9pN-6FmN^Mncv?n&&%Y8s$ktFIQU;f1`Yc2owr61>tg7j zK{R;4fGYY(M0@G2qz~>x;<|JeDK;vqC?Yg;vxmETv?2DBQ`YCx+2tp>Cj&}u-d0j&lqG*D%s@%7zE6U1);8XnFkfXrDD?WO`j&?8z* zdDxhM=o?A{GekKw5$ObCBrU&i9j|eE8LtU~2jz>Y6%`cmHB#(>AP7cO6j+wRDa+U5 zW5_^C#m{ht{BwDVj3eKz+a{T#D|*80DHaL}N0 z$unnOjyiGTvFtBnqK+R%Jg=Fb--%}a{wL;`n`h@D?g`ksgBYY$V}CgQV>f6QFwgt$ zcI$TJhXDhQNB{WaWt%!?S?O`a=<0#0U>hnuq~W4z(^KAdc1J$5u*g1F5vQlhyE2|% z!9U04>F8{S9I4lvHr=-XvA0b$WKrX7#Ms)nIytpQoNb+OScs|hkBvQlKrTQ0M4@Ze zx2n!1-laGM36IX$OU7hxA$|SLrS9(AGlmY$iAC&ewKxHF!XQT0(8JN8ue*bNxVqm} z?;$4C$jt0;ysmC$?x<1ubpCuH;=yiGbo6QR^gIMS4#&<&d{@*N1(sgon=!N!mYn0_ zHUQJN@oseVz7G)hS!W!JldWwFS6kZ!i1Dnk3=r2DgV@INTwgpq4wuKY-n&;qyLT7R zfBticTDLw-rl!n0>s!*f6a&DRc;;O>mX9&fYk*H*`yeqfeE_iIb@JUJM%B>O#(J)+ zOg2JQ-^$nE+a7dUicQqlPY3?=PsAZr#G(}!zo2vHp3+Z0-4Nq2_4QfjtZydfT^YkJ z;kY?2PZ5je;U1%E-@d`peNGV*s0-=^-mg{c?;zFlJ=Cewv1(&NIW9Ic^FF=*{t5E)+fI6VtZxZB zF7YnK{w+gn+|t5?gw%g3^H7^}nW<@a#Q7F{KWFxJ%&59Z?;x%Z<4wjg@Q%Kn`R2GY zZlhes(|}#yg?6C8AyhXL<2a?Ptb6p&e;y$N1IE9zzL^;Ry&SX*v>3DiW$^21#Owju zUi$;_dA2r2MvI+oY)TJhW-?%A1jtlJ=K$h<4%}4muC8y{NgX?8)6JWhe%A6xPrprl z`|iUS!1ZP+Xh|9G3z7Z^`i{Q%A}6u-+zSF?t8|>KEaS}e^sdEskEQ(FTrP(XJUz3L z5mSblbA`?oV`)X-!m(rv7F-th7^tNP#8~_lEB>UWP1ho3iTUO@3C74XE_4pHY`J731k<^fy^zyof6Q zjCWPW@+<$&IQs1D+cacI8v0z0d1HM0T+kfEoP3{g;J`Jyn=5Eo_JnbT1sC}nL@X&+!)kJP&lw|=dAB;;8AIjKwjGw?~RNIsT?KFu3)BNo9=1?wvc!>lfpq z4;{Ke;o;mbO#^*_KKqLfb>m(T5F4a}7`d)81A~0d&&R`q)~;G5mV?CCnKO^*i+a0)rc5~womSWt%>NU_V2n>rCiKyj@VboMGy~b0n*$e=MB5Rw!g-uMdzX6j zScS3TbM$?a-UjK`RR+Z7*f^M)UcfS_s5dX*vS*=9KYE0vN2P=1xO(*|?cIA5bt{wl z^w~uhE>tap!&zD6@8hF3{)FYQ)YBtu^h2MG`vmeA(TNkcU=Q+mF#ZtYO?X+c&WE#& z_4mNClAWO;*)rxG)Vq6k`UCMr&osn?78R8e%cSm@F>R_CGo}eM&2qp1qr|wl>uBF+ zj~%;F;@~i?7;yrV5iemYzGz`NhEW}_>h4{; zaz%{0Rc;5WvM~PF(!}KZyu7?{d?R)C>1khNX0k};6*u3g=Kqhf|x2!cV7+vRh5yS-;v|hcT&);YRsTP?N^g0(fPP|6p9IkCP*XBM#u>4?m>+d-l*( zwA~`;UOG6YQ-;1x!mguD?E-GShJG?R4DGlJsLta-n^vuSxR|?hq;B zjytvmP9IoO#vF6ZLI`3Of`K>YcmqC@|q%J}8^}{yyG|fPH>#xP47LtKJ8G)vR0Bu5tbP^jZ1Fpg|9Z4F-<4e}5VP zOmjczHWBezBHmq+Cn`#e+2^>BsPJ}=+O=+-8r;0uNZ>j#T>WTpdkAm-D7+8 zii=w`c;LVbz$CvAF}T31GyaxkV*GypgoNk7?qBT~5xy=oC@8*lixwWht(N!k{~ZY` z=L#&Xv5&WR)1X$ZdPIbW4+oC+9}(@^jf9Me-dCj zz$8;VUL|E16Th$6nIs%59pO0l0NlxnQ{b(PkbZ+ykJCIwx-X4kQdkk5s7UjX3b@Wg zQl3r_1iXe13j$D7Vk+Xl!UdsH>LCco78#1KD$~L%x^G(g#TMz!x%M zJeZMkD#EsKzf3MkPND)Mh1{$_{Qi=9N?cde(9B>IPdU{!Br%t^}>FJN)qr8Z<>`dgtK2E0HAol$z{8b7cKKo79 z!?(P3BX9>bu8YD)|B;KWZ55rtCl4QGRu22+t*kQX_HD(!pzQZuwdxi{L}bH1$37hRG><-8yJtNy9zj+Oo% zJ^GOP_df!Ef&y=$*vC!sowKiG8TKRH10Q$whozCx46HZg;?th|Bz()RDCfcozw%yS zK+*_%`YYvLaeDszV;VRx6Z%m0d$aF&3Gf&z*=JnseAH1UbB1s7Nyh&D`S>b^j{{>X z{K8T>@5CO8)vxDfW!-_Fi+yN|%ZPoa^Psx}9jn)XAlRFleA5Iz1o&!hBqg1_DEZNq z>$bjr3UC;TJ*yA?dBkJm|ro)FTa0Tqc3_}b&??DW#3ym2yiln_a z3kr&XqhJh*xW`{oO+2uF&d$VmBm1@f@zz`Ln=5=(XU{$YCguoq%Gi*f;X_NSqyygj zn0-~eW-RVK1YZ`fmGFMR>~rbWi`&HK*Fn}b@c`eH1J;`F^BOv@c@-$FSF;ax;lc~l zuH9zzN4Ls(U_WLg;@_3mteFox3k#Zwb;&1BiYY3J+rxxeHRaF0V=vcDy!L8~eRSX> zpv;Vn^1P&zXU_n~S334$uO3MU%6zada>UR#cHg@7_`Zk7S7_7Y+-u^&$JKR2efS{Q zr{aRWUmW05Nq+x*x_jr2QjS$mqp=r&a^8H-Yv6X47VS_^T5Q|)$8|lu@{V`>Wye5Z9#ftk1xKKmP$=hh0rP z1O)`V*%oWgiuGpforJyt>#^X)iQuyl{TaO0uX@B|9}V7LO(DDPb0=%7aOJ$PuTKLT zn+c~{SJCyp95aYR`AnST=Ql9@E$_Ej}q^PGPHj` z`enrmdZTY5c{w>w(Y$V*j9E-F#+aH9tcB|J?9qJ!_F{NCAhD0Qej5)zYaIGK1wZYf zpSGgkG7K1qR*f6qYUEYF#=fTJoGU-kqD2eO0sZ>U8l04r&-);-Pka#e%HTC}>?Kng z6V>T>hp@0QSbKdX>}=&+t6pI(RliZghTiSM!rEgUwKMju2&?Dm=~DGc?H#QK{&#CY zweJ+Kix7B+<(Ke@0-@uaun2@rqr&%N*(D8>S4LRUuqs>DFv5gLuZ(P72tpgsI1IMq zXd+_gcqymIL;SSrA6}<$1Ol9GJ|IwpyV^Dx(*b7S=AeHzOe|C47)2iPMwZ`{FL;R@!zoCmK9tfznd zE2q2*nl~H&{{j1K4ut)%XZLO~pEYa#!2cGSU86>y zF_bZFyoWnuk60g!8_dqW1I+F1av7E_Tv%zZSIpgL^r#PtH*7fl*u>po;}_=a$>aQeLZ8{zTT0wQR0Z0*o#&END3gFNcJM&7H*O z>W=3A{vN=lTyF=QO)zjnEr1Q;c|qIe&FFLdFNB=KhebT`(jAfTzcseI8EYZt2aE;F(;M^C*)yioZ2Zp??A^M< z-O*76yONA{TD_ee)1`C6{(TZtlKS;66|pO^u_A7z3-A!UPbT&Yy%XT)`x&qtHO?2* z>51>bb~fzUqet6;{ri93KQVDlVto9jUfsJd?HbkTt&pG~SJ=#I+pDJUY488N8bDiN zUr+_XdDTt`7upIQu%E1ii6R*ZX>d;EiKGV~mrfa(z|Un4-bSlO{n-z**Dn^ z;|`TmtsPdovW<>DXKi9~D8bAu>oY^cjA_2US??hhA`t(7R&AflUqwu#wd&WgzORco z(V+$gnOD*4!E~1Fn_UO??Y{Z!Z%yw=XP%P$!FR_$H8HW&R}<-^g+DjxWD*aZAPNYk?v z@j7Y1#UHJN#V#n|@1Di~wBzqB#kUte4-Q@nJEZb~7zkr8XXk_4x9&OP?|-O7u|B*5 zaco;@*Dl5S7_SLmzH~_(V)F7H;s0r}jWHMBUhsY8uPLtVO-&;M8~7EUIh~K#gY#v! z*+%#n_J}<4Iw<$e-J_#v!@6};RLC(SS+GTBb6w-tV zC&|leBc-HV5&7bA-4^i{yiVC1W7kH+qs*V54L{P<`GW9SmHybpPVR<1^Plj3;TzYl z7uRNsi=R_|zG6L`*Ma*1D_A~O11tS$^4R0a$=h!k7>o;0l^g3AI=~30GFF@S9Une$ z0G&K`Otdvb2Jt5wxPG=N6yMY-#h%j97cShzzkK`=>!=@A;jvXy|2Az~G%senYXIy9 z#)ys_G8l0xsUp6W?Ul7+HDW+gu>ZVh^Cu)M?_g;7vD!M`r9+3euqW;_-Yc2+ zNXGYp*=$0cfqk4dX%el%dY7-0<55?+OleIq8N4NXsLCu|$H&D*4eZ3`T~3G7PM^K_**}(`c~4jwN3qeeGPiY#|QQ8-FsL<&z|r0h>3{{32v>nZq)Xh z|KFYiz5!#8f?ntq2+2AHnEMw9*24Q3!xWT;J9)UHAjWD$VEjrGO7ZLqql)+WJ3L-- zhw2IXzc_Bemu+lsf4G@UmK8j9Y_7(-f^h>|nO7VbGYl}_9}u-yWjCYX4l^d3)|jE z`5W+&>UVA5em=Sc%uNrD;5^;kGchMo_&~C<3NWWVh(4QrO)D|x{FDWsW2OE9F>)i9 zE?l_N(edCZh0l5?&77Glb~W5D@R62w13okE|L4QUv#zBw5Ae?!cso0t*s=X6B_te0 zUYpUMr{MqKm56>3UXNb7Xc5jIQet8X3jMVF z=V`IA%T}oJfH5JF@#c*X55@a*uUxi_c#gscq}PZ3wTb@L|P6FndCvYr+1Bv+YdVohHsF(KhiV6rdp`Z@0{jrqo- zkmk)6VC`OGJ*@bq;*7@-V2GXCg|)3$&(jk=h5wxg%v|(4z;}h?zj~l&7dgeqGqH@) VP*d}m^wHm7c36OC_*v<_{{ce;R^$Kx literal 0 HcmV?d00001 diff --git a/resources/logo.png b/resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..eb406f53996d534c8b9f073d69a95b0465bdafe6 GIT binary patch literal 6548 zcmV;F8EfW=P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000iZNklInEbM{;s090UViQyUDtn>{YgTIpTz>)Zg*TCQwaI+rp$U4I?P(mu9P-uLbr_+te$!Sj(7ytO0t{Y98c6eTt z6TBQFJw5%({QN<0xLocbwYA>*pyL5Y-;X?tC<%4X28Ll0QbGiR3Kok@R;Met?z(>` zuUBsRt7|qCW_C2Xo;_3Yl&Y$Y?k50*fW)RP;A-IbWg(zLhm4$l{RVy@TM}|=YQ2c4 z){S}u#A@4!A>lkZ0yU%(2>6jL33TbwnL&g4Gi=yUZs_|f($Z3Saph{hKY9$8%RR4s zht8gg@{>CDgza{6H1p2F!+A&H{2S3jrx9DeZdqzW!}ZGjgy?XW8tm~q;ss-vaZbTfLfziOUW1O5}pad0yib7giD#L~i zVbrMG7&dGu85tcKmG}G$uTXOG1a^lj98pX(%`!7JHRE_?<>^(1QD4_pfDWiJe!&WT zfUAIGttOybw;sO}SVwrhzJ|`uFrwBF>*)={!0!v78#>oqlf#7ZV;M81fSjDGFDUEl zuMe?$^*WHOXqtu))a4DjPOVpZJ~=tA2Vy@n=)niM`<7dXoDWHsEg#LAwfx+V zKQ6Ph)(NJkx9^dZlsd=j^`4LA@!mWP+%yHcuH*Iku-dE)9MF#`QzlYSa4X5l$rmMW z+47YH{1qU%G0hmaCP{=8#qMypRygeTo0U)~dKQLHn#46jhD4VZ|KlHPD^Hzr$?!?5 zqCi4I0vVZ|7kj;aw{FD6_(%vd&xbIt*N4;LVD#wQnK9#DZn|m6CCNK*;49vJ_gx^V ziI^wh^C?48Qc@=j8l{VLWug= zoFT#lnD~5tBuQfU@S!|8XC{LO4``9KEnD^?y5m%M7N)=yf>0<#ND0!fUti|U zo6V?Ex3$>M?A`m{?0kPaNJ-5k^)f!6(mOfXH6joQ?kp%M0I&nAPaiyZ-`?fRalnfb zs8VYPNK8y@r)gqTFsOvJFA&0v#(pJOOS|+8R;*aWjOq8{a5!2F-ZV{~etJ2Eu7Kof zcDK}qz$&TIump_lJfllrGu(!bwx{9>zbw_ z%pkYlK9Xh27Lk{i+v)`C(@+1(zI}U|*M4jQ!2*6bZ~!~3 z0K5%8a4A<~k^~(xIxn%=I|!>aT_hy56SBo4z$xsGG_iE)^TISuaWO+FFBjqhYfaM> zHw_ylAVDCdHa~F-kVL=yVQOjV=^7z~_;&ktF%QIi_+bGgEdXMtxYT0EZnvZB3{*qv z`AS20$;#@+#*OP3HtfRQU9GOBZ0}yaUAK-zkB7l;ywT*^KmYl^*t_SG=Cv>CGJjdN z@!OeCvgqk~)}*8)Yvr+Hygz+9a$QBZJe(c3ycm)si6mFr-PP5Bf#-$S(tp5>Y}~Mx z?%lgJzCY8X{Iky}+PamJ4?m=)qy!Tv*tf6Fq#7BzuCwTw72!P2egW_yK;^pY`tj`I zrx|hUZ~$tHi}};Iari4Lu)+~wQ>&}NeP)HGp6#;Lo?{mp?!3T zucU-+ciu_aH{al_s{%Jku&-7909lquO7c8jSrr%&IrEdJ+{cFXtFc0za}}i>HOgJ^_w~LKYs&~=+!Hav13OvVZvB?^~!7VGl$o#;jc4i zqACjZuE{rh3F*_!qhen0zv^BcZ- z{q?AG72(={;DQBHuNpmiquI>8LS}w`(-z=#IvuJeFVVFiR;!)D!c}zb+J#V25#QZ& z4;B0OV*zZ9Xk5fuf(cyp$RkaHk5rgjwyeYLb~mfFb6^6kM6+)k~1^UdV2OeBFi#DmRm-E!{Kyl zsyx#)s~9mulEKLAn4f>ZmYiIDG1_mG07-(Rq}2Z?FR#h%+_?vTq!H# zyXDI{zGe-fU@)3Yi8#&2`k4;hyPxVjV#Ll%z8$V_{;n~VmF3sWdi+U7j2ONUSOlP- zI6?4V|3a=~{XHaUAwpymqlI|wCue7K#r^kR67W!28Aa>X@x!WBc+1MLgu`omgrSk2 zy=Ki?nUI)R(_#V~4!gzYH-4L!cRfP}T|aO8_U(%Svb%OA?eBjFMXCEjfe^Jw(p=!p z3;przdGoMbgjWX$78P;g)mJHAzaHP2GxZXx__J=tWRH>GhiF6u;{f3y2M)wD zW=zAsQB=g)En6ttyczFz-$jAiVgSV_R8k{^MAn3WPJ;)3)n~#tJqjw2-m~Yi{#&+8l&sc3s|c{$ombi&4*A^K;y*T3Kb#166rEurV(WCt zZhys=oUAG5&b^#5ZJO0RbSTvyeMIGs9aQhyMex+AC=hEixkLOBXzaX)fQ5jwf1^U?l*wYuDkrV6b+Bs;W&^59fe0K(}}T>iXBnF4x*bm+LH=w)RNx-tB#d z4@XVd(nt)KVzeycuCV0`5Mu(_hYXyZRc68%l^zStE($MztBPrD84}b zEDQrnO3DuX?Ad{4ZS9V5GZHyGBMvn7xv}>fn^Kr`XZ!Xweb%g*-FMrzg3AFuY5^xt z7N5GPB&E5`Pt&kwWgSb%%p7MwabkjU^ypKe($Z_;;=ZoZz_7x=6C4gB>%RLoUo~gW zVn=rNQNp*+@ - + \ No newline at end of file diff --git a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj index f6dd3bce..e07a4f74 100644 --- a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj +++ b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj @@ -45,8 +45,8 @@ ..\..\packages\EntityFramework.6.1.3\lib\net40\EntityFramework.SqlServer.dll True - - ..\..\packages\JetBrains.Annotations.10.4.0\lib\net\JetBrains.Annotations.dll + + ..\..\packages\JetBrains.Annotations.2022.1.0\lib\net20\JetBrains.Annotations.dll ..\..\packages\SQLite.CodeFirst.1.3.0.17\lib\net40\SQLite.CodeFirst.dll diff --git a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config index d211ee36..fef02f4e 100644 --- a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config +++ b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000..622dd61d --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,26 @@ + + + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + ../../resources/logo.ico + ZZZ Projects;Stef Heyenrath + ZZZ Projects + Copyright © ZZZ Projects + en-us + true + latest + enable + logo.png + Apache-2.0 + https://dynamic-linq.net/ + Bugfixes and new Features. For details see CHANGELOG.md + true + true + git + https://github.com/zzzprojects/System.Linq.Dynamic.Core + true + + + + + + diff --git a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj index a09bf679..e9105fdc 100644 --- a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj +++ b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj @@ -2,32 +2,15 @@ - 1.2.$(PatchVersion) - Dynamic Linq extensions for EntityFramework which adds Async support - EntityFramework.DynamicLinq - ZZZ Projects;Stef Heyenrath - net45;net452;net46;netstandard2.1 - EF;EFDYNAMICFUNCTIONS - true EntityFramework.DynamicLinq EntityFramework.DynamicLinq.snk - true - true + EntityFramework.DynamicLinq + EF;EFDYNAMICFUNCTIONS + Dynamic Linq extensions for EntityFramework which adds Async support system;linq;dynamic;entityframework;core;async - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {D3804228-91F4-4502-9595-39584E510000} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + net45;net452;net46;netstandard2.1 + 1.2.$(PatchVersion) @@ -35,9 +18,6 @@ - portable true @@ -55,7 +35,10 @@ - + + + + diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj index 5b869177..6537b112 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj @@ -2,32 +2,15 @@ - 2.2.$(PatchVersion) - Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support - Microsoft.EntityFrameworkCore.DynamicLinq - ZZZ Projects;Stef Heyenrath - netstandard2.0 - $(DefineConstants);EFCORE;EFCORE_2X;EFDYNAMICFUNCTIONS - true Microsoft.EntityFrameworkCore.DynamicLinq Microsoft.EntityFrameworkCore.DynamicLinq.snk - true - true + Microsoft.EntityFrameworkCore.DynamicLinq + $(DefineConstants);EFCORE;EFCORE_2X;EFDYNAMICFUNCTIONS + Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support system;linq;dynamic;entityframework;core;async - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {D3804228-91F4-4502-9595-39584E510001} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + netstandard2.0 + 2.2.$(PatchVersion) @@ -35,9 +18,6 @@ - portable true @@ -59,7 +39,7 @@ - + diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj index 4d764773..e2e34391 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj @@ -2,32 +2,15 @@ - 3.2.$(PatchVersion) - Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support - Microsoft.EntityFrameworkCore.DynamicLinq - ZZZ Projects;Stef Heyenrath - netstandard2.0 - $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE - true Microsoft.EntityFrameworkCore.DynamicLinq ../Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.snk - true - true + Microsoft.EntityFrameworkCore.DynamicLinq + $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE + Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support system;linq;dynamic;entityframework;core;async - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {7994FECC-965C-4A5D-8B0E-1A6EA769D4BE} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + netstandard2.0 + 3.2.$(PatchVersion) @@ -58,7 +41,7 @@ - + diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj index 2b557897..c879d151 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj @@ -2,32 +2,15 @@ - 5.2.$(PatchVersion) - Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support - Microsoft.EntityFrameworkCore.DynamicLinq - ZZZ Projects;Stef Heyenrath - netstandard2.1;net5.0 - $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE - true Microsoft.EntityFrameworkCore.DynamicLinq ../Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.snk - true - true + Microsoft.EntityFrameworkCore.DynamicLinq + $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE + Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support system;linq;dynamic;entityframework;core;async - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {D3804228-91F4-4502-9595-39584E519901} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + netstandard2.1;net5.0 + 5.2.$(PatchVersion) @@ -59,7 +42,7 @@ - + \ No newline at end of file diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj index 55e8b65c..03f1ce55 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj @@ -2,32 +2,15 @@ - 6.2.$(PatchVersion) - Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support - Microsoft.EntityFrameworkCore.DynamicLinq - ZZZ Projects;Stef Heyenrath - net6.0 - $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE - true Microsoft.EntityFrameworkCore.DynamicLinq ../Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.snk - true - true + Microsoft.EntityFrameworkCore.DynamicLinq + $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE + Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support system;linq;dynamic;entityframework;core;async - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {D28F6393-B56B-40A2-AF67-E8D669F42546} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + net6.0 + 6.2.$(PatchVersion) @@ -59,7 +42,7 @@ - + \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj b/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj index 1814848f..0d06a5e7 100644 --- a/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj +++ b/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj @@ -2,31 +2,15 @@ - 1.2.$(PatchVersion) - This is a .NETStandard / .NET Core port of the the Microsoft assembly for the .Net 4.0 Dynamic language functionality. - System.Linq.Dynamic.Core - ZZZ Projects;Stef Heyenrath;Microsoft;Scott Guthrie;King Wilder;Nathan Arnott - net35;net40;net45;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;uap10.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0 - true System.Linq.Dynamic.Core System.Linq.Dynamic.Core.snk - true - + System.Linq.Dynamic.Core + ZZZ Projects;Stef Heyenrath;Microsoft;Scott Guthrie;King Wilder;Nathan Arnott + This is a .NETStandard / .NET Core port of the the Microsoft assembly for the .Net 4.0 Dynamic language functionality. system;linq;dynamic;core;dotnet;NETCoreApp;NETStandard - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {D3804228-91F4-4502-9595-39584E510002} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + net35;net40;net45;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;uap10.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0 + 1.2.$(PatchVersion) @@ -75,7 +59,7 @@ - + diff --git a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj index 1b653e3d..88fd58ce 100644 --- a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj +++ b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj @@ -2,32 +2,15 @@ - 1.2.$(PatchVersion) - Dynamic Linq extensions for Z.EntityFramework.Classic which adds Async support - Z.EntityFramework.Classic.DynamicLinq - ZZZ Projects;Stef Heyenrath - net45;netstandard2.0 - EF - true Z.EntityFramework.Classic.DynamicLinq Z.EntityFramework.Classic.DynamicLinq.snk - true - true + Z.EntityFramework.Classic.DynamicLinq + EF + Dynamic Linq extensions for Z.EntityFramework.Classic which adds Async support system;linq;dynamic;Z.EntityFramework;core;async;classic - Bugfixes and new Features. For details see CHANGELOG.md - https://dynamic-linq.net/ - Apache-2.0 - https://zzzprojects.github.io/images/logo/logo-64.png - git - https://github.com/zzzprojects/System.Linq.Dynamic.Core - en-us {D3804228-91F4-4502-9595-39584Ea20000} - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - ZZZ Projects - Copyright © ZZZ Projects - 10 - enable + net45;netstandard2.0 + 1.2.$(PatchVersion) @@ -35,9 +18,6 @@ - portable true @@ -55,7 +35,7 @@ - + \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj b/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj index 76ac497e..6f3f1075 100644 --- a/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj +++ b/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj @@ -7,7 +7,6 @@ True ../../src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.snk false - $(DefineConstants);NETCOREAPP;EFCORE;EFCORE_3X;NETCOREAPP3_1 @@ -22,13 +21,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - diff --git a/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj b/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj index 8e1bbc39..84e96058 100644 --- a/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj +++ b/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj @@ -13,8 +13,8 @@ - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -26,13 +26,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - @@ -54,8 +50,8 @@ - - - + + + diff --git a/version.xml b/version.xml index 95293eb3..640df83f 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 20 + 21-preview-01 From fca6cb22f91f7de8057114f2aa2ed722c57643bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 20 Oct 2022 18:08:23 +0200 Subject: [PATCH 002/214] fixes #580 (#630) uses the topmost implementation of the virtual method --- .../Parser/SupportedMethods/MethodFinder.cs | 2 +- .../Parser/MethodFinderTest.cs | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs index 1e2a8efe..af4a29c7 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs @@ -105,7 +105,7 @@ public int FindBestMethodBasedOnArguments(IEnumerable methods, ref E if (applicable.Length == 1) { MethodData md = applicable[0]; - method = md.MethodBase; + method = ((MethodInfo)md.MethodBase).GetBaseDefinition(); args = md.Args; } else diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs new file mode 100644 index 00000000..91b9d655 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Linq.Expressions; +using static System.Console; +using static System.Linq.Expressions.Expression; +using System.Linq.Dynamic.Core.Parser; +using System.Linq.Dynamic.Core; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests.Parser +{ + public class MethodFinderTest + { + [Fact] + public void MethodsOfDynamicLinqAndSystemLinqShouldBeEqual() + { + Expression> expr = x => x.ToString(); + + var selector = "ToString()"; + var prm = Parameter(typeof(int?)); + var parser = new ExpressionParser(new[] { prm }, selector, new object[] { }, ParsingConfig.Default); + var expr1 = parser.Parse(null); + + Assert.Equal(((MethodCallExpression)expr.Body).Method.DeclaringType, ((MethodCallExpression)expr1).Method.DeclaringType); + } + } +} From abb8c039bfe47dc4ac9d33e3230edc1d8eb50ba8 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Thu, 20 Oct 2022 21:56:44 +0200 Subject: [PATCH 003/214] Fix MethodFinder.cs --- .../Parser/SupportedMethods/MethodFinder.cs | 14 +++++++++++--- .../System.Linq.Dynamic.Core.Tests.csproj | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs index af4a29c7..cdfcf7a7 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs @@ -104,9 +104,17 @@ public int FindBestMethodBasedOnArguments(IEnumerable methods, ref E if (applicable.Length == 1) { - MethodData md = applicable[0]; - method = ((MethodInfo)md.MethodBase).GetBaseDefinition(); - args = md.Args; + var methodData = applicable[0]; + if (methodData.MethodBase is MethodInfo methodInfo) + { + method = methodInfo.GetBaseDefinition(); + } + else + { + method = methodData.MethodBase; + } + + args = methodData.Args; } else { diff --git a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj index 9cef8bb9..a4473c01 100644 --- a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj +++ b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj @@ -5,6 +5,7 @@ System.Linq.Dynamic.Core.Tests full True + 10 ../../src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.snk {912FBF24-3CAE-4A50-B5EA-E525B9FAEC80} From 3703828bf77eee76c0777dccf68b42cecda2b0c3 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 23 Oct 2022 10:51:11 +0200 Subject: [PATCH 004/214] Fix nullable issues (#636) * DefaultDynamicLinqCustomTypeProvider * . * . * . * . * x * . * . * . --- System.Linq.Dynamic.Core.sln.DotSettings | 4 +- src/Directory.Build.props | 2 +- ...ueryableWithFormattableStringExtensions.cs | 1 + .../Compatibility/ExpressionVisitor.cs | 50 +- .../Compatibility/StringExtensions.cs | 39 + .../AbstractDynamicLinqCustomTypeProvider.cs | 21 +- .../DefaultDynamicLinqCustomTypeProvider.cs | 12 +- .../IDynamicLinqCustomTypeProvider.cs | 6 +- .../DefaultQueryableAnalyzer.cs | 95 ++- .../DynamicClassFactory.cs | 39 +- .../DynamicEnumerableAsyncExtensions.cs | 213 +++--- .../DynamicEnumerableExtensions.cs | 51 +- .../DynamicExpressionParser.cs | 97 +-- .../DynamicGetMemberBinder.cs | 91 ++- .../DynamicQueryableExtensions.cs | 679 +++++++++--------- ...ueryableWithFormattableStringExtensions.cs | 9 +- src/System.Linq.Dynamic.Core/GroupResult.cs | 6 +- .../IQueryableAnalyzer.cs | 25 +- .../ParameterExpressionHelper.cs | 66 +- .../Parser/ConstantExpressionHelper.cs | 8 +- .../Parser/Constants.cs | 13 +- .../Parser/ExpressionHelper.cs | 32 +- .../Parser/ExpressionParser.cs | 304 ++++---- .../Parser/ExpressionPromoter.cs | 24 +- .../Parser/IExpressionHelper.cs | 2 +- .../Parser/IExpressionPromoter.cs | 8 +- .../Parser/ITypeFinder.cs | 5 +- .../Parser/NumberParser.cs | 37 +- .../Parser/PredefinedTypesHelper.cs | 2 +- .../Parser/SupportedMethods/MethodFinder.cs | 30 +- .../Parser/TypeFinder.cs | 33 +- .../Parser/TypeHelper.cs | 26 +- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 23 +- .../Tokenizer/TextParser.cs | 13 +- .../TypeConverters/CustomDateTimeConverter.cs | 31 +- .../TypeConverters/ITypeConverterFactory.cs | 24 +- .../TypeConverters/TypeConverterFactory.cs | 13 +- .../Util/ParameterExpressionRenamer.cs | 108 ++- .../Util/QueryableMethodFinder.cs | 65 +- .../CallerArgumentExpressionAttribute.cs | 15 + .../Validation/Check.cs | 185 +++-- .../Validation/CoreStrings.cs | 49 +- .../Parser/ParameterExpressionHelperTests.cs | 2 +- 43 files changed, 1269 insertions(+), 1289 deletions(-) create mode 100644 src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs create mode 100644 src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs diff --git a/System.Linq.Dynamic.Core.sln.DotSettings b/System.Linq.Dynamic.Core.sln.DotSettings index 40a1a991..13649a33 100644 --- a/System.Linq.Dynamic.Core.sln.DotSettings +++ b/System.Linq.Dynamic.Core.sln.DotSettings @@ -1,5 +1,7 @@  EF + IL UTC WASM - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 622dd61d..b4e615fc 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,7 +7,7 @@ Copyright © ZZZ Projects en-us true - latest + 10 enable logo.png Apache-2.0 diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs index aa2e2433..2a75ae60 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs @@ -13,6 +13,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +#pragma warning disable CS1591 using JetBrains.Annotations; using System.Text.RegularExpressions; diff --git a/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs b/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs index 475cdd7b..3f1cd563 100644 --- a/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs +++ b/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs @@ -19,7 +19,9 @@ protected ExpressionVisitor() protected virtual Expression Visit(Expression exp) { if (exp == null) + { return exp; + } switch (exp.NodeType) { @@ -103,7 +105,7 @@ protected virtual MemberBinding VisitBinding(MemberBinding binding) protected virtual ElementInit VisitElementInitializer(ElementInit initializer) { - ReadOnlyCollection arguments = this.VisitExpressionList(initializer.Arguments); + ReadOnlyCollection arguments = VisitExpressionList(initializer.Arguments); if (arguments != initializer.Arguments) { return Expression.ElementInit(initializer.AddMethod, arguments); @@ -127,13 +129,15 @@ protected virtual Expression VisitBinary(BinaryExpression b) { Expression left = Visit(b.Left); Expression right = Visit(b.Right); - Expression conversion = Visit(b.Conversion); + Expression conversion = Visit(b.Conversion!); if (left != b.Left || right != b.Right || conversion != b.Conversion) { if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) + { return Expression.Coalesce(left, right, conversion as LambdaExpression); - else - return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); + } + + return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); } return b; @@ -186,8 +190,8 @@ protected virtual Expression VisitMemberAccess(MemberExpression m) protected virtual Expression VisitMethodCall(MethodCallExpression m) { - Expression obj = Visit(m.Object); - IEnumerable args = this.VisitExpressionList(m.Arguments); + Expression obj = Visit(m.Object!); + IEnumerable args = VisitExpressionList(m.Arguments); if (obj != m.Object || args != m.Arguments) { return Expression.Call(obj, m.Method, args); @@ -198,10 +202,10 @@ protected virtual Expression VisitMethodCall(MethodCallExpression m) protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection original) { - List list = null; + List? list = null; for (int i = 0, n = original.Count; i < n; i++) { - Expression p = this.Visit(original[i]); + Expression p = Visit(original[i]); if (list != null) { list.Add(p); @@ -239,7 +243,7 @@ protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assign protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) { - IEnumerable bindings = this.VisitBindingList(binding.Bindings); + IEnumerable bindings = VisitBindingList(binding.Bindings); if (bindings != binding.Bindings) { return Expression.MemberBind(binding.Member, bindings); @@ -250,7 +254,7 @@ protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBindi protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) { - IEnumerable initializers = this.VisitElementInitializerList(binding.Initializers); + IEnumerable initializers = VisitElementInitializerList(binding.Initializers); if (initializers != binding.Initializers) { return Expression.ListBind(binding.Member, initializers); @@ -261,10 +265,10 @@ protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding bin protected virtual IEnumerable VisitBindingList(ReadOnlyCollection original) { - List list = null; + List? list = null; for (int i = 0, n = original.Count; i < n; i++) { - MemberBinding b = this.VisitBinding(original[i]); + MemberBinding b = VisitBinding(original[i]); if (list != null) { list.Add(b); @@ -288,10 +292,10 @@ protected virtual IEnumerable VisitBindingList(ReadOnlyCollection protected virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original) { - List list = null; + List? list = null; for (int i = 0, n = original.Count; i < n; i++) { - ElementInit init = this.VisitElementInitializer(original[i]); + ElementInit init = VisitElementInitializer(original[i]); if (list != null) { list.Add(init); @@ -326,7 +330,7 @@ protected virtual Expression VisitLambda(LambdaExpression lambda) protected virtual NewExpression VisitNew(NewExpression nex) { - IEnumerable args = this.VisitExpressionList(nex.Arguments); + IEnumerable args = VisitExpressionList(nex.Arguments); if (args != nex.Arguments) { if (nex.Members != null) @@ -341,7 +345,7 @@ protected virtual NewExpression VisitNew(NewExpression nex) protected virtual Expression VisitMemberInit(MemberInitExpression init) { NewExpression n = VisitNew(init.NewExpression); - IEnumerable bindings = this.VisitBindingList(init.Bindings); + IEnumerable bindings = VisitBindingList(init.Bindings); if (n != init.NewExpression || bindings != init.Bindings) { return Expression.MemberInit(n, bindings); @@ -353,7 +357,7 @@ protected virtual Expression VisitMemberInit(MemberInitExpression init) protected virtual Expression VisitListInit(ListInitExpression init) { NewExpression n = VisitNew(init.NewExpression); - IEnumerable initializers = this.VisitElementInitializerList(init.Initializers); + IEnumerable initializers = VisitElementInitializerList(init.Initializers); if (n != init.NewExpression || initializers != init.Initializers) { return Expression.ListInit(n, initializers); @@ -364,17 +368,15 @@ protected virtual Expression VisitListInit(ListInitExpression init) protected virtual Expression VisitNewArray(NewArrayExpression na) { - IEnumerable exprs = this.VisitExpressionList(na.Expressions); + IEnumerable exprs = VisitExpressionList(na.Expressions); if (exprs != na.Expressions) { if (na.NodeType == ExpressionType.NewArrayInit) { - return Expression.NewArrayInit(na.Type.GetElementType(), exprs); - } - else - { - return Expression.NewArrayBounds(na.Type.GetElementType(), exprs); + return Expression.NewArrayInit(na.Type.GetElementType()!, exprs); } + + return Expression.NewArrayBounds(na.Type.GetElementType()!, exprs); } return na; @@ -382,7 +384,7 @@ protected virtual Expression VisitNewArray(NewArrayExpression na) protected virtual Expression VisitInvocation(InvocationExpression iv) { - IEnumerable args = this.VisitExpressionList(iv.Arguments); + IEnumerable args = VisitExpressionList(iv.Arguments); Expression expr = Visit(iv.Expression); if (args != iv.Arguments || expr != iv.Expression) { diff --git a/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs b/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs new file mode 100644 index 00000000..c84575fe --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs @@ -0,0 +1,39 @@ +// ReSharper disable once CheckNamespace +namespace System; + +internal static class StringExtensions +{ + /// + /// Indicates whether a specified string is null, empty, or consists only of white-space + /// characters. + /// + /// Recreates the same functionality as System.String.IsNullOrWhiteSpace but included here + /// for compatibility with net35. + /// + /// The string to test. + /// + /// true if the value parameter is null or System.String.Empty, or if value consists + /// exclusively of white-space characters. + /// + public static bool IsNullOrWhiteSpace(this string? value) + { +#if !NET35 + return string.IsNullOrWhiteSpace(value); +#else + if (value == null) + { + return true; + } + + for (int i = 0; i < value.Length; i++) + { + if (!char.IsWhiteSpace(value[i])) + { + return false; + } + } + + return true; +#endif + } +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs index ec367fd4..811b7d10 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq.Dynamic.Core.Validation; using System.Reflection; @@ -15,7 +14,7 @@ public abstract class AbstractDynamicLinqCustomTypeProvider /// /// The assemblies to process. /// - protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) + protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) { Check.NotNull(assemblies, nameof(assemblies)); #if !NET35 @@ -30,7 +29,7 @@ protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull /// The assemblies to inspect. /// The typename to resolve. /// A resolved or null when not found. - protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull] string typeName) + protected Type? ResolveType(IEnumerable assemblies, string typeName) { Check.NotNull(assemblies, nameof(assemblies)); Check.NotEmpty(typeName, nameof(typeName)); @@ -53,19 +52,19 @@ protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull] /// The assemblies to inspect. /// The simple typename to resolve. /// A resolved or null when not found. - protected Type ResolveTypeBySimpleName([NotNull] IEnumerable assemblies, [NotNull] string simpleTypeName) + protected Type? ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) { Check.NotNull(assemblies, nameof(assemblies)); Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); foreach (var assembly in assemblies) { - var fullNames = assembly.GetTypes().Select(t => t.FullName).Distinct(); + var fullNames = assembly.GetTypes().Select(t => t.FullName!).Distinct(); var firstMatchingFullname = fullNames.FirstOrDefault(fn => fn.EndsWith($".{simpleTypeName}")); if (firstMatchingFullname != null) { - Type resolvedType = assembly.GetType(firstMatchingFullname, false, true); + var resolvedType = assembly.GetType(firstMatchingFullname, false, true); if (resolvedType != null) { return resolvedType; @@ -82,13 +81,13 @@ protected Type ResolveTypeBySimpleName([NotNull] IEnumerable assemblie /// /// The assemblies to process. /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) { Check.NotNull(assemblies, nameof(assemblies)); foreach (var assembly in assemblies) { - Type[] definedTypes = null; + Type[]? definedTypes = null; try { @@ -118,13 +117,13 @@ protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNul /// /// The assemblies to process. /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) { Check.NotNull(assemblies, nameof(assemblies)); foreach (var assembly in assemblies.Where(a => !a.GlobalAssemblyCache)) // Skip System DLL's { - Type[] definedTypes = null; + Type[]? definedTypes = null; try { diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs index 859e6d97..e6fc9430 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs @@ -6,7 +6,7 @@ namespace System.Linq.Dynamic.Core.CustomTypeProviders { /// - /// The default implementation for . + /// The default implementation for . /// /// Scans the current AppDomain for all types marked with , and adds them as custom Dynamic Link types. /// @@ -19,8 +19,8 @@ public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTyp private readonly IAssemblyHelper _assemblyHelper = new DefaultAssemblyHelper(); private readonly bool _cacheCustomTypes; - private HashSet _cachedCustomTypes; - private Dictionary> _cachedExtensionMethods; + private HashSet? _cachedCustomTypes; + private Dictionary>? _cachedExtensionMethods; /// /// Initializes a new instance of the class. @@ -64,7 +64,7 @@ public Dictionary> GetExtensionMethods() } /// - public Type ResolveType(string typeName) + public Type? ResolveType(string typeName) { Check.NotEmpty(typeName, nameof(typeName)); @@ -73,7 +73,7 @@ public Type ResolveType(string typeName) } /// - public Type ResolveTypeBySimpleName(string simpleTypeName) + public Type? ResolveTypeBySimpleName(string simpleTypeName) { Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); @@ -106,4 +106,4 @@ private Dictionary> GetExtensionMethodsInternal() return list.GroupBy(x => x.Item1, tuple => tuple.Item2).ToDictionary(key => key.Key, methods => methods.ToList()); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs index 1ccd8800..4d950612 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs @@ -26,13 +26,13 @@ public interface IDynamicLinqCustomTypeProvider /// /// The typename to resolve. /// A resolved or null when not found. - Type ResolveType([NotNull] string typeName); + Type? ResolveType(string typeName); /// /// Resolve any type by the simple name which is registered in the current application domain. /// /// The typename to resolve. /// A resolved or null when not found. - Type ResolveTypeBySimpleName([NotNull] string simpleTypeName); + Type? ResolveTypeBySimpleName(string simpleTypeName); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs b/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs index a9136777..9c637f22 100644 --- a/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs +++ b/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs @@ -1,71 +1,68 @@ using System.Linq.Dynamic.Core.Validation; using System.Reflection; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Default implementation. +/// +/// +public class DefaultQueryableAnalyzer : IQueryableAnalyzer { - /// - /// Default implementation. - /// - /// - public class DefaultQueryableAnalyzer : IQueryableAnalyzer + /// + public bool SupportsLinqToObjects(IQueryable query, IQueryProvider? provider = null) { - /// - public bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null) - { - Check.NotNull(query, nameof(query)); - provider = provider ?? query.Provider; + Check.NotNull(query, nameof(query)); + provider = provider ?? query.Provider; - Type providerType = provider.GetType(); - Type baseType = providerType.GetTypeInfo().BaseType; + Type providerType = provider.GetType(); + Type baseType = providerType.GetTypeInfo().BaseType!; #if NET35 - bool isLinqToObjects = baseType.FullName.Contains("EnumerableQuery"); + bool isLinqToObjects = baseType.FullName!.Contains("EnumerableQuery"); #else - bool isLinqToObjects = baseType == typeof(EnumerableQuery); + bool isLinqToObjects = baseType == typeof(EnumerableQuery); #endif - if (!isLinqToObjects) + if (!isLinqToObjects) + { + // Support for https://github.com/StefH/QueryInterceptor.Core, version 1.0.1 and up + if (providerType.Name.StartsWith("QueryTranslatorProvider")) { - // Support for https://github.com/StefH/QueryInterceptor.Core, version 1.0.1 and up - if (providerType.Name.StartsWith("QueryTranslatorProvider")) + try { - try - { - PropertyInfo property = providerType.GetProperty("OriginalProvider"); - if (property != null) - { - IQueryProvider originalProvider = property.GetValue(provider, null) as IQueryProvider; - return originalProvider != null && SupportsLinqToObjects(query, originalProvider); - } - - return SupportsLinqToObjects(query); - } - catch + var property = providerType.GetProperty("OriginalProvider"); + if (property != null) { - return false; + return property.GetValue(provider, null) is IQueryProvider originalProvider && SupportsLinqToObjects(query, originalProvider); } - } - // Support for https://github.com/scottksmith95/LINQKit ExpandableQuery - if (providerType.Name.StartsWith("ExpandableQuery")) + return SupportsLinqToObjects(query); + } + catch { - try - { - PropertyInfo property = query.GetType().GetProperty("InnerQuery", BindingFlags.NonPublic | BindingFlags.Instance); - if (property != null) - { - IQueryable innerQuery = property.GetValue(query, null) as IQueryable; - return innerQuery != null && SupportsLinqToObjects(innerQuery, provider); - } + return false; + } + } - return SupportsLinqToObjects(query); - } - catch + // Support for https://github.com/scottksmith95/LINQKit ExpandableQuery + if (providerType.Name.StartsWith("ExpandableQuery")) + { + try + { + var property = query.GetType().GetProperty("InnerQuery", BindingFlags.NonPublic | BindingFlags.Instance); + if (property != null) { - return false; + return property.GetValue(query, null) is IQueryable innerQuery && SupportsLinqToObjects(innerQuery, provider); } + + return SupportsLinqToObjects(query); + } + catch + { + return false; } } - - return isLinqToObjects; } + + return isLinqToObjects; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs b/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs index abbb7545..d705ffe3 100644 --- a/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs +++ b/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs @@ -22,20 +22,20 @@ namespace System.Linq.Dynamic.Core /// public static class DynamicClassFactory { - private static readonly ConcurrentDictionary GeneratedTypes = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary GeneratedTypes = new(); private static readonly ModuleBuilder ModuleBuilder; // Some objects we cache - private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]); - private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never }); - private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]); + private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]); + private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never }); + private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]); - private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes); + private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes)!; #if WINDOWS_APP || UAP10_0 || NETSTANDARD - private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public); + private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public)!; #else - private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); + private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null)!; #endif private static readonly ConstructorInfo StringBuilderCtor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes); @@ -43,20 +43,20 @@ public static class DynamicClassFactory private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", new[] { typeof(string) }); private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", new[] { typeof(object) }); #else - private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null); - private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null); + private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null)!; + private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null)!; #endif private static readonly Type EqualityComparer = typeof(EqualityComparer<>); private static readonly Type EqualityComparerGenericArgument = EqualityComparer.GetGenericArguments()[0]; #if WINDOWS_APP || UAP10_0 || NETSTANDARD - private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public); - private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }); - private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", new[] { EqualityComparerGenericArgument }); + private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public)!; + private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument })!; + private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", new[] { EqualityComparerGenericArgument })!; #else - private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); - private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null); - private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null); + private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null)!; + private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null)!; + private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null)!; #endif private static int _index = -1; @@ -105,9 +105,9 @@ public static Type CreateGenericComparerType(Type comparerGenericType, Type comp { if (!GeneratedTypes.TryGetValue(key, out type)) { - var compareMethodGeneric = comparerGenericType.GetMethod("Compare"); + var compareMethodGeneric = comparerGenericType.GetMethod("Compare")!; var compareMethod = typeof(IComparer).GetMethod("Compare"); - var compareCtor = comparerType.GetConstructor(Type.EmptyTypes); + var compareCtor = comparerType.GetConstructor(Type.EmptyTypes)!; var genericType = comparerGenericType.GetGenericArguments()[0]; var typeBuilder = ModuleBuilder.DefineType(key, TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoLayout, typeof(object)); @@ -170,7 +170,7 @@ public static Type CreateGenericComparerType(Type comparerGenericType, Type comp /// ]]> /// /// - public static Type CreateType([NotNull] IList properties, bool createParameterCtor = true) + public static Type CreateType(IList properties, bool createParameterCtor = true) { Check.HasNoNulls(properties, nameof(properties)); @@ -179,8 +179,7 @@ public static Type CreateType([NotNull] IList properties, bool string key = GenerateKey(properties, createParameterCtor); - Type type; - if (!GeneratedTypes.TryGetValue(key, out type)) + if (!GeneratedTypes.TryGetValue(key, out var type)) { // We create only a single class at a time, through this lock // Note that this is a variant of the double-checked locking. diff --git a/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs index 97faa375..98b32d1b 100644 --- a/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs @@ -7,136 +7,129 @@ using System.Threading.Tasks; using JetBrains.Annotations; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Define async extensions on . +/// +public static class DynamicEnumerableAsyncExtensions { + private static readonly MethodInfo ToListAsyncGenericMethod; + + static DynamicEnumerableAsyncExtensions() + { + ToListAsyncGenericMethod = typeof(DynamicEnumerableAsyncExtensions).GetTypeInfo() + .GetDeclaredMethods("ToListAsync") + .First(x => x.IsGenericMethod); + } + /// - /// Define async extensions on . + /// Async creates an array of dynamic objects from a . /// - public static class DynamicEnumerableAsyncExtensions + /// A to create an array from. + /// A cast to. + /// The (optional). + /// An Array that contains the elements from the input sequence. + [PublicAPI] + public static async Task ToDynamicArrayAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) { - private static readonly MethodInfo ToListAsyncGenericMethod; - - static DynamicEnumerableAsyncExtensions() - { - ToListAsyncGenericMethod = typeof(DynamicEnumerableAsyncExtensions).GetTypeInfo() - .GetDeclaredMethods("ToListAsync") - .First(x => x.IsGenericMethod); - } - - /// - /// Async creates an array of dynamic objects from a . - /// - /// A to create an array from. - /// A cast to. - /// The (optional). - /// An Array that contains the elements from the input sequence. - [PublicAPI] - public static async Task ToDynamicArrayAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); - - var result = await ToDynamicListAsync(source, type, cancellationToken).ConfigureAwait(false); - return result.ToArray(); - } + var result = await ToDynamicListAsync(Check.NotNull(source), Check.NotNull(type), cancellationToken).ConfigureAwait(false); + return result.ToArray(); + } - /// - /// Async creates an array of dynamic objects from a . - /// - /// A to create an array from. - /// The (optional). - /// An array that contains the elements from the input sequence. - [PublicAPI] - public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return (await ToListAsync(source, cancellationToken).ConfigureAwait(false)).ToArray(); - } + /// + /// Async creates an array of dynamic objects from a . + /// + /// A to create an array from. + /// The (optional). + /// An array that contains the elements from the input sequence. + [PublicAPI] + public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return (await ToListAsync(Check.NotNull(source), cancellationToken).ConfigureAwait(false)).ToArray(); + } - /// - /// Async creates an array of dynamic objects from a . - /// - /// The generic type. - /// A to create an array from. - /// The (optional). - /// An Array{T} that contains the elements from the input sequence. - [PublicAPI] - public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return (await ToListAsync(source, cancellationToken).ConfigureAwait(false)).ToArray(); - } + /// + /// Async creates an array of dynamic objects from a . + /// + /// The generic type. + /// A to create an array from. + /// The (optional). + /// An Array{T} that contains the elements from the input sequence. + [PublicAPI] + public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return (await ToListAsync(Check.NotNull(source), cancellationToken).ConfigureAwait(false)).ToArray(); + } - /// - /// Async creates a list of dynamic objects from a . - /// - /// A to create an array from. - /// A cast to. - /// The (optional). - /// An List that contains the elements from the input sequence. - [PublicAPI] - public static async Task> ToDynamicListAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + /// + /// Async creates a list of dynamic objects from a . + /// + /// A to create an array from. + /// A cast to. + /// The (optional). + /// An List that contains the elements from the input sequence. + [PublicAPI] + public static async Task> ToDynamicListAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) + { + Check.NotNull(source); + Check.NotNull(type); - var task = (Task)ToListAsyncGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source, cancellationToken })!; + var task = (Task)ToListAsyncGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source, cancellationToken })!; - await task.ConfigureAwait(false); + await task.ConfigureAwait(false); - var list = (IList)task.GetType().GetProperty(nameof(Task.Result))!.GetValue(task)!; + var list = (IList)task.GetType().GetProperty(nameof(Task.Result))!.GetValue(task)!; - return list.Cast().ToList(); - } + return list.Cast().ToList(); + } - /// - /// Async creates a list of dynamic objects from a . - /// - /// A to create a list from. - /// The (optional). - /// A List that contains the elements from the input sequence. - [PublicAPI] - public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return ToListAsync(source, cancellationToken); - } + /// + /// Async creates a list of dynamic objects from a . + /// + /// A to create a list from. + /// The (optional). + /// A List that contains the elements from the input sequence. + [PublicAPI] + public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return ToListAsync(Check.NotNull(source), cancellationToken); + } - /// - /// Async creates a list of dynamic objects from an . - /// - /// Generic Type - /// A to create a list from. - /// The (optional). - /// A List{T} that contains the elements from the input sequence. - [PublicAPI] - public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return ToListAsync(source, cancellationToken); - } + /// + /// Async creates a list of dynamic objects from an . + /// + /// Generic Type + /// A to create a list from. + /// The (optional). + /// A List{T} that contains the elements from the input sequence. + [PublicAPI] + public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return ToListAsync(Check.NotNull(source), cancellationToken); + } #pragma warning disable CS1998 - private static async Task> ToListAsync(IEnumerable source, CancellationToken cancellationToken) + // ReSharper disable once UnusedParameter.Local + private static async Task> ToListAsync(IEnumerable source, CancellationToken cancellationToken) #pragma warning restore CS1998 + { + switch (source) { - switch (source) - { #if NETSTANDARD2_1_OR_GREATER || ASYNCENUMERABLE - case IAsyncEnumerable asyncEnumerable: - var list = new List(); - await foreach (var element in asyncEnumerable.WithCancellation(cancellationToken).ConfigureAwait(false)) - { - list.Add(element); - } - return list; + case IAsyncEnumerable asyncEnumerable: + var list = new List(); + await foreach (var element in asyncEnumerable.WithCancellation(cancellationToken).ConfigureAwait(false)) + { + list.Add(element); + } + return list; #endif - case IEnumerable enumerable: - return enumerable.ToList(); + case IEnumerable enumerable: + return enumerable.ToList(); - default: - return source.Cast().ToList(); - } + default: + return source.Cast().ToList(); } } } diff --git a/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs index 85bc93b7..b669fafe 100644 --- a/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Linq.Dynamic.Core.Validation; using System.Reflection; @@ -25,16 +24,14 @@ static DynamicEnumerableExtensions() /// A to create an array from. /// An array that contains the elements from the input sequence. #if NET35 - public static object[] ToDynamicArray([NotNull] this IEnumerable source) + public static object[] ToDynamicArray(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToArray(source); + return CastToArray(Check.NotNull(source)); } #else - public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source) + public static dynamic[] ToDynamicArray(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToArray(source); + return CastToArray(Check.NotNull(source)); } #endif @@ -44,10 +41,9 @@ public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source) /// The generic type. /// A to create an array from. /// An Array{T} that contains the elements from the input sequence. - public static T[] ToDynamicArray([NotNull] this IEnumerable source) + public static T[] ToDynamicArray(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToArray(source); + return CastToArray(Check.NotNull(source)); } /// @@ -57,13 +53,13 @@ public static T[] ToDynamicArray([NotNull] this IEnumerable source) /// A cast to. /// An Array that contains the elements from the input sequence. #if NET35 - public static object[] ToDynamicArray([NotNull] this IEnumerable source, [NotNull] Type type) + public static object[] ToDynamicArray(this IEnumerable source, Type type) #else - public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source, [NotNull] Type type) + public static dynamic[] ToDynamicArray(this IEnumerable source, Type type) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + Check.NotNull(source); + Check.NotNull(type); IEnumerable result = (IEnumerable)ToDynamicArrayGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source }); #if NET35 @@ -79,16 +75,15 @@ public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source, [NotNu /// A to create an array from. /// A List that contains the elements from the input sequence. #if NET35 - public static List ToDynamicList([NotNull] this IEnumerable source) + public static List ToDynamicList(this IEnumerable source) #else - public static List ToDynamicList([NotNull] this IEnumerable source) + public static List ToDynamicList(this IEnumerable source) #endif { - Check.NotNull(source, nameof(source)); #if NET35 - return CastToList(source); + return CastToList(Check.NotNull(source)); #else - return CastToList(source); + return CastToList(Check.NotNull(source)); #endif } @@ -99,15 +94,12 @@ public static List ToDynamicList([NotNull] this IEnumerable source) /// A cast to. /// A List that contains the elements from the input sequence. #if NET35 - public static List ToDynamicList([NotNull] this IEnumerable source, [NotNull] Type type) + public static List ToDynamicList(this IEnumerable source, Type type) #else - public static List ToDynamicList([NotNull] this IEnumerable source, [NotNull] Type type) + public static List ToDynamicList(this IEnumerable source, Type type) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); - - return ToDynamicArray(source, type).ToList(); + return ToDynamicArray(Check.NotNull(source), Check.NotNull(type)).ToList(); } /// @@ -116,10 +108,9 @@ public static List ToDynamicList([NotNull] this IEnumerable source, [No /// Generic Type /// A to create an array from. /// A List{T} that contains the elements from the input sequence. - public static List ToDynamicList([NotNull] this IEnumerable source) + public static List ToDynamicList(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToList(source); + return CastToList(Check.NotNull(source)); } internal static T[] CastToArray(IEnumerable source) @@ -132,4 +123,4 @@ internal static List CastToList(IEnumerable source) return source.Cast().ToList(); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index 02e286cb..c0629715 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -21,7 +21,7 @@ public static class DynamicExpressionParser /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -41,7 +41,7 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -60,7 +60,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, typeof(TResult), expression, values); } @@ -76,8 +76,9 @@ public static Expression> ParseLambda([CanBeNull] Parsing /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, typeof(TResult), expression, values); } @@ -92,7 +93,7 @@ public static Expression> ParseLambda([NotNull] Type dele /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]? values) { return ParseLambda(null, parsingConfig, createParameterCtor, parameters, resultType, expression, values); } @@ -109,10 +110,8 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]? values) { - LambdaExpression lambdaExpression = null; - Check.NotNull(parameters, nameof(parameters)); Check.HasNoNulls(parameters, nameof(parameters)); Check.NotEmpty(expression, nameof(expression)); @@ -121,30 +120,21 @@ public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBe var parsedExpression = parser.Parse(resultType, createParameterCtor); - if (parsingConfig != null && parsingConfig.RenameParameterExpression && parameters.Length == 1) + LambdaExpression lambdaExpression; + if (parsingConfig is { RenameParameterExpression: true } && parameters.Length == 1) { var renamer = new ParameterExpressionRenamer(parser.LastLambdaItName); parsedExpression = renamer.Rename(parsedExpression, out ParameterExpression newParameterExpression); - if (delegateType == null) - { - lambdaExpression = Expression.Lambda(parsedExpression, new[] { newParameterExpression }); - } - else - { - lambdaExpression = Expression.Lambda(delegateType, parsedExpression, new[] { newParameterExpression }); - } + lambdaExpression = delegateType == null ? + Expression.Lambda(parsedExpression, newParameterExpression) : + Expression.Lambda(delegateType, parsedExpression, newParameterExpression); } else { - if (delegateType == null) - { - lambdaExpression = Expression.Lambda(parsedExpression, parameters); - } - else - { - lambdaExpression = Expression.Lambda(delegateType, parsedExpression, parameters); - } + lambdaExpression = delegateType == null ? + Expression.Lambda(parsedExpression, parameters) : + Expression.Lambda(delegateType, parsedExpression, parameters); } return lambdaExpression; @@ -161,7 +151,7 @@ public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBe /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[] values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, parameters, typeof(TResult), expression, values); } @@ -178,8 +168,10 @@ public static Expression> ParseLambda([CanBeNull] Parsing /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, parameters, typeof(TResult), expression, values); } @@ -193,7 +185,7 @@ public static Expression> ParseLambda([NotNull] Type dele /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -212,7 +204,7 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] T /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -231,8 +223,9 @@ public static Expression> ParseLambda([CanBeNull] P /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); Check.NotEmpty(expression, nameof(expression)); return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, new[] { ParameterExpressionHelper.CreateParameterExpression(typeof(T), string.Empty, parsingConfig?.RenameEmptyParameterExpressionNames ?? false) }, typeof(TResult), expression, values); @@ -247,7 +240,7 @@ public static Expression> ParseLambda([NotNull] Typ /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[] values) { return ParseLambda(parsingConfig, true, resultType, expression, values); } @@ -262,8 +255,10 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return ParseLambda(delegateType, parsingConfig, true, resultType, expression, values); } @@ -275,7 +270,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type? resultType, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -284,7 +279,7 @@ public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull // DO NOT ADD: It create ambiguous method error //[PublicAPI] - //public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + //public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBeNull] Type resultType, [NotNull] string expression, params object?[]values) //{ // Check.NotEmpty(expression, nameof(expression)); @@ -300,8 +295,10 @@ public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type itType, Type? resultType, string expression, params object?[] values) { + Check.NotNull(itType, nameof(itType)); + return ParseLambda(true, itType, resultType, expression, values); } @@ -315,8 +312,10 @@ public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Ty /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[] values) { + Check.NotNull(itType, nameof(itType)); + return ParseLambda(parsingConfig, true, itType, resultType, expression, values); } @@ -331,8 +330,11 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + Check.NotNull(itType, nameof(itType)); + return ParseLambda(delegateType, parsingConfig, true, itType, resultType, expression, values); } @@ -347,7 +349,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]? values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -367,8 +369,9 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -384,7 +387,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(null, true, parameters, resultType, expression, values); } @@ -399,8 +402,10 @@ public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] param /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return ParseLambda(delegateType, null, true, parameters, resultType, expression, values); } @@ -414,7 +419,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [NotNull /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(parsingConfig, true, parameters, resultType, expression, values); } @@ -430,8 +435,10 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return ParseLambda(delegateType, parsingConfig, true, parameters, resultType, expression, values); } @@ -445,9 +452,9 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(null, createParameterCtor, parameters, resultType, expression, values); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs b/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs index 2b1b3f83..f2369f44 100644 --- a/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs +++ b/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs @@ -4,65 +4,64 @@ using System.Dynamic; using System.Linq.Expressions; using System.Reflection; -using JetBrains.Annotations; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Code is based on SqlLinq by dkackman (https://github.com/dkackman/SqlLinq/blob/210b594e37f14061424397368ed750ce547c21e7/License.md) however it's modified to solve several issues. +/// +/// +internal class DynamicGetMemberBinder : GetMemberBinder { - /// - /// Code is based on SqlLinq by dkackman (https://github.com/dkackman/SqlLinq/blob/210b594e37f14061424397368ed750ce547c21e7/License.md) however it's modified to solve several issues. - /// - /// - internal class DynamicGetMemberBinder : GetMemberBinder + private static readonly MethodInfo DynamicGetMemberMethod = typeof(DynamicGetMemberBinder).GetMethod(nameof(GetDynamicMember))!; + + public DynamicGetMemberBinder(string name, ParsingConfig? config) : base(name, config?.IsCaseSensitive != true) + { + } + + public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject? errorSuggestion) { - private static readonly MethodInfo DynamicGetMemberMethod = typeof(DynamicGetMemberBinder).GetMethod(nameof(GetDynamicMember)); + var instance = Expression.Call( + DynamicGetMemberMethod, + target.Expression, + Expression.Constant(Name), + Expression.Constant(IgnoreCase)); - public DynamicGetMemberBinder(string name, [CanBeNull] ParsingConfig config) : base(name, !(config?.IsCaseSensitive == true)) + return DynamicMetaObject.Create(target.Value!, instance); + } + + public static object? GetDynamicMember(object value, string name, bool ignoreCase) + { + if (value == null) { + throw new InvalidOperationException(); } - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) + if (value is IDictionary stringObjectDictionary) { - var instance = Expression.Call( - DynamicGetMemberMethod, - target.Expression, - Expression.Constant(Name), - Expression.Constant(IgnoreCase)); - - return DynamicMetaObject.Create(target.Value, instance); + return stringObjectDictionary[name]; } - public static object GetDynamicMember(object value, string name, bool ignoreCase) + if (value is IDictionary nonGenericDictionary) { - if (value == null) - { - throw new InvalidOperationException(); - } - - if (value is IDictionary stringObjectDictionary) - { - return stringObjectDictionary[name]; - } - - if (value is IDictionary nonGenericDictionary) - { - return nonGenericDictionary[name]; - } - - var flags = BindingFlags.Instance | BindingFlags.Public; - if (ignoreCase) - { - flags |= BindingFlags.IgnoreCase; - } + return nonGenericDictionary[name]; + } - var type = value.GetType(); - var property = type.GetProperty(name, flags); - if (property == null) - { - throw new InvalidOperationException($"Unable to find property '{name}' on type '{type}'."); - } + var flags = BindingFlags.Instance | BindingFlags.Public; + if (ignoreCase) + { + flags |= BindingFlags.IgnoreCase; + } - return property.GetValue(value, null); + var type = value.GetType(); + var property = type.GetProperty(name, flags); + if (property == null) + { + throw new InvalidOperationException($"Unable to find property '{name}' on type '{type}'."); } + + return property.GetValue(value, null); } } -#endif + +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index d4e27c7f..a9a72943 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq.Dynamic.Core.Exceptions; #if !(WINDOWS_APP45x || SILVERLIGHT) @@ -24,10 +25,11 @@ namespace System.Linq.Dynamic.Core /// It allows dynamic string based querying. Very handy when, at compile time, you don't know the type of queries that will be generated, /// or when downstream components only return column names to sort and filter by. /// + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] public static class DynamicQueryableExtensions { #if !(WINDOWS_APP45x || SILVERLIGHT) - private static readonly TraceSource TraceSource = new TraceSource(nameof(DynamicQueryableExtensions)); + private static readonly TraceSource TraceSource = new(nameof(DynamicQueryableExtensions)); #endif private static Expression OptimizeExpression(Expression expression) @@ -57,25 +59,25 @@ private static Expression OptimizeExpression(Expression expression) /// The name of the function to run. Can be Sum, Average, Min or Max. /// The name of the property to aggregate over. /// The value of the aggregate function run over the specified property. - public static object Aggregate([NotNull] this IQueryable source, [NotNull] string function, [NotNull] string member) + public static object Aggregate(this IQueryable source, string function, string member) { - Check.NotNull(source, nameof(source)); - Check.NotEmpty(function, nameof(function)); - Check.NotEmpty(member, nameof(member)); + Check.NotNull(source); + Check.NotEmpty(function); + Check.NotEmpty(member); // Properties - PropertyInfo property = source.ElementType.GetProperty(member); + PropertyInfo property = source.ElementType.GetProperty(member)!; ParameterExpression parameter = ParameterExpressionHelper.CreateParameterExpression(source.ElementType, "s"); Expression selector = Expression.Lambda(Expression.MakeMemberAccess(parameter, property), parameter); // We've tried to find an expression of the type Expression>, // which is expressed as ( (TSource s) => s.Price ); - var methods = typeof(Queryable).GetMethods().Where(x => x.Name == function && x.IsGenericMethod); + var methods = typeof(Queryable).GetMethods().Where(x => x.Name == function && x.IsGenericMethod).ToArray(); // Method - MethodInfo aggregateMethod = methods.SingleOrDefault(m => + MethodInfo? aggregateMethod = methods.SingleOrDefault(m => { - ParameterInfo lastParameter = m.GetParameters().LastOrDefault(); + var lastParameter = m.GetParameters().LastOrDefault(); return lastParameter != null && TypeHelper.GetUnderlyingType(lastParameter.ParameterType) == property.PropertyType; }); @@ -87,7 +89,7 @@ public static object Aggregate([NotNull] this IQueryable source, [NotNull] strin Expression.Call( null, aggregateMethod.MakeGenericMethod(source.ElementType), - new[] { source.Expression, Expression.Quote(selector) })); + new[] { source.Expression, Expression.Quote(selector) }))!; } // Min, Max @@ -96,8 +98,8 @@ public static object Aggregate([NotNull] this IQueryable source, [NotNull] strin return source.Provider.Execute( Expression.Call( null, - aggregateMethod.MakeGenericMethod(source.ElementType, property.PropertyType), - new[] { source.Expression, Expression.Quote(selector) })); + aggregateMethod!.MakeGenericMethod(source.ElementType, property.PropertyType), + new[] { source.Expression, Expression.Quote(selector) }))!; } #endregion Aggregate @@ -110,7 +112,7 @@ public static object Aggregate([NotNull] this IQueryable source, [NotNull] strin /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. [PublicAPI] - public static bool All([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static bool All(this IQueryable source, string predicate, params object?[] args) { return All(source, ParsingConfig.Default, predicate, args); } @@ -122,11 +124,11 @@ public static bool All([NotNull] this IQueryable source, [NotNull] string predic /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. [PublicAPI] - public static bool All([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) + public static bool All(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(createParameterCtor, source.ElementType, null, predicate, args); @@ -149,11 +151,9 @@ public static bool All([NotNull] this IQueryable source, [NotNull] ParsingConfig /// /// /// true if the source sequence contains any elements; otherwise, false. - public static bool Any([NotNull] this IQueryable source) + public static bool Any(this IQueryable source) { - Check.NotNull(source, nameof(source)); - - return Execute(_any, source); + return Execute(_any, Check.NotNull(source)); } private static readonly MethodInfo _anyPredicate = QueryableMethodFinder.GetMethod(nameof(Queryable.Any), 1); @@ -175,11 +175,11 @@ public static bool Any([NotNull] this IQueryable source) /// /// true if the source sequence contains any elements; otherwise, false. [PublicAPI] - public static bool Any([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static bool Any(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -188,7 +188,7 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] ParsingConfig } /// - public static bool Any([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static bool Any(this IQueryable source, string predicate, params object?[] args) { return Any(source, ParsingConfig.Default, predicate, args); } @@ -199,10 +199,10 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] string predic /// A sequence to check for being empty. /// A cached Lambda Expression. /// true if the source sequence contains any elements; otherwise, false. - public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static bool Any(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_anyPredicate, source, lambda); } @@ -222,9 +222,9 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpress /// /// The average of the values in the sequence. [PublicAPI] - public static double Average([NotNull] this IQueryable source) + public static double Average(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var average = QueryableMethodFinder.GetMethod(nameof(Queryable.Average), source.ElementType, typeof(double)); return Execute(average, source); @@ -245,11 +245,11 @@ public static double Average([NotNull] this IQueryable source) /// /// The average of the values in the sequence. [PublicAPI] - public static double Average([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static double Average(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -259,7 +259,7 @@ public static double Average([NotNull] this IQueryable source, [NotNull] Parsing /// [PublicAPI] - public static double Average([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static double Average(this IQueryable source, string predicate, params object?[] args) { return Average(source, ParsingConfig.Default, predicate, args); } @@ -271,10 +271,10 @@ public static double Average([NotNull] this IQueryable source, [NotNull] string /// A Lambda Expression. /// The average of the values in the sequence. [PublicAPI] - public static double Average([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static double Average(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); var averageSelector = QueryableMethodFinder.GetMethod(nameof(Queryable.Average), lambda.GetReturnType(), typeof(double), 1); return Execute(averageSelector, source, lambda); @@ -288,14 +288,14 @@ public static double Average([NotNull] this IQueryable source, [NotNull] LambdaE /// /// The sequence to type as of . /// The input typed as of . - public static IEnumerable AsEnumerable([NotNull] this IQueryable source) + public static IEnumerable AsEnumerable(this IQueryable source) #else /// /// Returns the input typed as of dynamic. /// /// The sequence to type as of dynamic. /// The input typed as of dynamic. - public static IEnumerable AsEnumerable([NotNull] this IQueryable source) + public static IEnumerable AsEnumerable(this IQueryable source) #endif { foreach (var obj in source) @@ -314,12 +314,12 @@ public static IEnumerable AsEnumerable([NotNull] this IQueryable source /// The that contains the elements to be converted. /// The type to convert the elements of source to. /// An that contains each element of the source sequence converted to the specified type. - public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Type type) + public static IQueryable Cast(this IQueryable source, Type type) { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + Check.NotNull(source); + Check.NotNull(type); - var optimized = OptimizeExpression(Expression.Call(null, _cast.MakeGenericMethod(new Type[] { type }), new Expression[] { source.Expression })); + var optimized = OptimizeExpression(Expression.Call(null, _cast.MakeGenericMethod(new[] { type }), new[] { source.Expression })); return source.Provider.CreateQuery(optimized); } @@ -331,14 +331,14 @@ public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Type t /// The . /// The type to convert the elements of source to. /// An that contains each element of the source sequence converted to the specified type. - public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName) + public static IQueryable Cast(this IQueryable source, ParsingConfig config, string typeName) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(typeName, nameof(typeName)); var finder = new TypeFinder(config, new KeywordsHelper(config)); - Type type = finder.FindTypeByName(typeName, null, true); + Type type = finder.FindTypeByName(typeName, null, true)!; return Cast(source, type); } @@ -349,7 +349,7 @@ public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Parsin /// The that contains the elements to be converted. /// The type to convert the elements of source to. /// An that contains each element of the source sequence converted to the specified type. - public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] string typeName) + public static IQueryable Cast(this IQueryable source, string typeName) { return Cast(source, ParsingConfig.Default, typeName); } @@ -369,9 +369,9 @@ public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] string /// /// /// The number of elements in the input sequence. - public static int Count([NotNull] this IQueryable source) + public static int Count(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_count, source); } @@ -395,11 +395,11 @@ public static int Count([NotNull] this IQueryable source) /// /// The number of elements in the specified sequence that satisfies a condition. [PublicAPI] - public static int Count([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static int Count(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -408,7 +408,7 @@ public static int Count([NotNull] this IQueryable source, [NotNull] ParsingConfi } /// - public static int Count([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static int Count(this IQueryable source, string predicate, params object?[] args) { return Count(source, ParsingConfig.Default, predicate, args); } @@ -419,10 +419,10 @@ public static int Count([NotNull] this IQueryable source, [NotNull] string predi /// The that contains the elements to be counted. /// A cached Lambda Expression. /// The number of elements in the specified sequence that satisfies a condition. - public static int Count([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static int Count(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_countPredicate, source, lambda); } @@ -442,9 +442,9 @@ public static int Count([NotNull] this IQueryable source, [NotNull] LambdaExpres /// /// /// An that contains default if source is empty; otherwise, source. - public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source) + public static IQueryable DefaultIfEmpty(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return CreateQuery(_defaultIfEmpty, source); } @@ -460,9 +460,9 @@ public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source) /// /// /// An that contains defaultValue if source is empty; otherwise, source. - public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source, [CanBeNull] object defaultValue) + public static IQueryable DefaultIfEmpty(this IQueryable source, object? defaultValue) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return CreateQuery(_defaultIfEmptyWithParam, source, Expression.Constant(defaultValue)); } @@ -483,9 +483,9 @@ public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source, [CanBe /// /// /// An that contains distinct elements from the source sequence. - public static IQueryable Distinct([NotNull] this IQueryable source) + public static IQueryable Distinct(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return CreateQuery(_distinct, source); } @@ -500,12 +500,12 @@ public static IQueryable Distinct([NotNull] this IQueryable source) /// The to return the first element of. /// The first element in source. #if NET35 - public static object First([NotNull] this IQueryable source) + public static object First(this IQueryable source) #else - public static dynamic First([NotNull] this IQueryable source) + public static dynamic First(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_first, source); } @@ -522,14 +522,14 @@ public static dynamic First([NotNull] this IQueryable source) /// The first element in source that passes the test in predicate. [PublicAPI] #if NET35 - public static object First([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object First(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic First([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic First(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -539,9 +539,9 @@ public static dynamic First([NotNull] this IQueryable source, [NotNull] ParsingC /// #if NET35 - public static object First([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object First(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic First([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic First(this IQueryable source, string predicate, params object?[] args) #endif { return First(source, ParsingConfig.Default, predicate, args); @@ -554,12 +554,12 @@ public static dynamic First([NotNull] this IQueryable source, [NotNull] string p /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object First([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object First(this IQueryable source, LambdaExpression lambda) #else - public static dynamic First([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic First(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_firstPredicate, source, lambda); } #endregion First @@ -574,12 +574,12 @@ public static dynamic First([NotNull] this IQueryable source, [NotNull] LambdaEx /// The to return the first element of. /// default if source is empty; otherwise, the first element in source. #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source) + public static object FirstOrDefault(this IQueryable source) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source) + public static dynamic FirstOrDefault(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_firstOrDefault, source); } @@ -594,14 +594,14 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source) /// default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. [PublicAPI] #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object FirstOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic FirstOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -611,9 +611,9 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] /// #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object FirstOrDefault(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic FirstOrDefault(this IQueryable source, string predicate, params object?[] args) #endif { return FirstOrDefault(source, ParsingConfig.Default, predicate, args); @@ -626,12 +626,12 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] /// A cached Lambda Expression. /// default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object FirstOrDefault(this IQueryable source, LambdaExpression lambda) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic FirstOrDefault(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_firstOrDefaultPredicate, source, lambda); } @@ -655,7 +655,7 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] /// /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, object[] args) { return InternalGroupBy(source, config, keySelector, resultSelector, null, args); } @@ -671,23 +671,23 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] Par /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A where each element represents a projection over a group and its key. - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer, object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer? equalityComparer, object[]? args) { return InternalGroupBy(source, config, keySelector, resultSelector, equalityComparer, args); } - internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer, object[] args) + internal static IQueryable InternalGroupBy(IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer? equalityComparer, object[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(keySelector, nameof(keySelector)); Check.NotEmpty(resultSelector, nameof(resultSelector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args); LambdaExpression elementLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, resultSelector, args); - Expression optimized = null; + Expression? optimized; if (equalityComparer == null) { optimized = OptimizeExpression(Expression.Call( @@ -710,13 +710,13 @@ internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, object[] args) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector, args); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer, object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer, object[] args) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector, equalityComparer, args); } @@ -736,13 +736,13 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)", "new (StringProperty1, StringProperty2)"); /// /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector) { return GroupBy(source, config, keySelector, resultSelector, null, null); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector); } @@ -757,13 +757,13 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// A string expression to specify a result value from each group. /// The comparer to use. /// A where each element represents a projection over a group and its key. - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer equalityComparer) { return InternalGroupBy(source, config, keySelector, resultSelector, equalityComparer, null); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector, equalityComparer); } @@ -784,7 +784,7 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, params object[]? args) { return InternalGroupBy(source, config, keySelector, null, args); } @@ -799,22 +799,21 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] Par /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The comparer to use. /// A where each element represents a projection over a group and its key. - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, IEqualityComparer equalityComparer, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, IEqualityComparer equalityComparer, params object[]? args) { return InternalGroupBy(source, config, keySelector, equalityComparer, args); } - internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, IEqualityComparer equalityComparer, [CanBeNull] params object[] args) + internal static IQueryable InternalGroupBy(IQueryable source, ParsingConfig config, string keySelector, IEqualityComparer? equalityComparer, params object[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(keySelector, nameof(keySelector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args); - Expression optimized = null; - + Expression? optimized; if (equalityComparer == null) { optimized = OptimizeExpression(Expression.Call( @@ -835,13 +834,13 @@ internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, params object[]? args) { return GroupBy(source, ParsingConfig.Default, keySelector, args); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, IEqualityComparer equalityComparer, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, IEqualityComparer equalityComparer, params object[]? args) { return GroupBy(source, ParsingConfig.Default, keySelector, equalityComparer, args); } @@ -858,11 +857,11 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// The . /// expressions to specify the keys for each element. /// A of type where each element represents a projection over a group, its key, and its subgroups. - public static IEnumerable GroupByMany([NotNull] this IEnumerable source, [NotNull] ParsingConfig config, params string[] keySelectors) + public static IEnumerable GroupByMany(this IEnumerable source, ParsingConfig config, params string[] keySelectors) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.HasNoNulls(keySelectors, nameof(keySelectors)); + Check.NotNull(source); + Check.NotNull(config); + Check.HasNoNulls(keySelectors); var selectors = new List>(keySelectors.Length); @@ -877,7 +876,7 @@ public static IEnumerable GroupByMany([NotNull] this IEnu } /// - public static IEnumerable GroupByMany([NotNull] this IEnumerable source, params string[] keySelectors) + public static IEnumerable GroupByMany(this IEnumerable source, params string[] keySelectors) { return GroupByMany(source, ParsingConfig.Default, keySelectors); } @@ -890,10 +889,10 @@ public static IEnumerable GroupByMany([NotNull] this IEnu /// A whose elements to group. /// Lambda expressions to specify the keys for each element. /// A of type where each element represents a projection over a group, its key, and its subgroups. - public static IEnumerable GroupByMany([NotNull] this IEnumerable source, params Func[] keySelectors) + public static IEnumerable GroupByMany(this IEnumerable source, params Func[] keySelectors) { - Check.NotNull(source, nameof(source)); - Check.HasNoNulls(keySelectors, nameof(keySelectors)); + Check.NotNull(source); + Check.HasNoNulls(keySelectors); return GroupByManyInternal(source, keySelectors, 0); } @@ -902,7 +901,7 @@ private static IEnumerable GroupByManyInternal(IEnumerabl { if (currentSelector >= keySelectors.Length) { - return null; + return null!; // TODO } var selector = keySelectors[currentSelector]; @@ -932,10 +931,10 @@ private static IEnumerable GroupByManyInternal(IEnumerabl /// A dynamic function to create a result element from an element from the first sequence and a collection of matching elements from the second sequence. /// An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. /// An obtained by performing a grouped join on two sequences. - public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable GroupJoin(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { Check.NotNull(outer, nameof(outer)); - Check.NotNull(config, nameof(config)); + Check.NotNull(config); Check.NotNull(inner, nameof(inner)); Check.NotEmpty(outerKeySelector, nameof(outerKeySelector)); Check.NotEmpty(innerKeySelector, nameof(innerKeySelector)); @@ -944,7 +943,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] Pa Type outerType = outer.ElementType; Type innerType = inner.AsQueryable().ElementType; - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, outer); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, outer); LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args); LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args); @@ -969,7 +968,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] Pa } /// - public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return GroupJoin(outer, ParsingConfig.Default, inner, outerKeySelector, innerKeySelector, resultSelector, args); } @@ -987,12 +986,12 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] IE /// A dynamic function to create a result element from two matching elements. /// An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. /// An obtained by performing an inner join on two sequences. - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { //http://stackoverflow.com/questions/389094/how-to-create-a-dynamic-linq-join-extension-method Check.NotNull(outer, nameof(outer)); - Check.NotNull(config, nameof(config)); + Check.NotNull(config); Check.NotNull(inner, nameof(inner)); Check.NotEmpty(outerKeySelector, nameof(outerKeySelector)); Check.NotEmpty(innerKeySelector, nameof(innerKeySelector)); @@ -1001,7 +1000,7 @@ public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] Parsing Type outerType = outer.ElementType; Type innerType = inner.AsQueryable().ElementType; - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, outer); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, outer); LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args); LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args); @@ -1029,7 +1028,7 @@ public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] Parsing } /// - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return Join(outer, ParsingConfig.Default, inner, outerKeySelector, innerKeySelector, resultSelector, args); } @@ -1047,13 +1046,13 @@ public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumer /// An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. /// This overload only works on elements where both sequences and the resulting element match. /// An that has elements of type TResult obtained by performing an inner join on two sequences. - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return (IQueryable)Join(outer, config, (IEnumerable)inner, outerKeySelector, innerKeySelector, resultSelector, args); } /// - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return Join(outer, ParsingConfig.Default, inner, outerKeySelector, innerKeySelector, resultSelector, args); } @@ -1069,12 +1068,12 @@ public static IQueryable Join([NotNull] this IQueryableThe to return the last element of. /// The last element in source. #if NET35 - public static object Last([NotNull] this IQueryable source) + public static object Last(this IQueryable source) #else - public static dynamic Last([NotNull] this IQueryable source) + public static dynamic Last(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_last, source); } @@ -1088,14 +1087,14 @@ public static dynamic Last([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object Last([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Last(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic Last([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic Last(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -1105,9 +1104,9 @@ public static dynamic Last([NotNull] this IQueryable source, [NotNull] ParsingCo /// #if NET35 - public static object Last([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object Last(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic Last([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic Last(this IQueryable source, string predicate, params object?[] args) #endif { return Last(source, ParsingConfig.Default, predicate, args); @@ -1121,12 +1120,12 @@ public static dynamic Last([NotNull] this IQueryable source, [NotNull] string pr /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object Last([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Last(this IQueryable source, LambdaExpression lambda) #else - public static dynamic Last([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic Last(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_lastPredicate, source, lambda); } #endregion Last @@ -1141,12 +1140,12 @@ public static dynamic Last([NotNull] this IQueryable source, [NotNull] LambdaExp /// The to return the last element of. /// default if source is empty; otherwise, the last element in source. #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source) + public static object LastOrDefault(this IQueryable source) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source) + public static dynamic LastOrDefault(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_lastDefault, source); } @@ -1160,14 +1159,14 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object LastOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic LastOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -1177,9 +1176,9 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] /// #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object LastOrDefault(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic LastOrDefault(this IQueryable source, string predicate, params object?[] args) #endif { return LastOrDefault(source, ParsingConfig.Default, predicate, args); @@ -1192,12 +1191,12 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object LastOrDefault(this IQueryable source, LambdaExpression lambda) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic LastOrDefault(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_lastDefaultPredicate, source, lambda); } #endregion LastOrDefault @@ -1217,9 +1216,9 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] /// /// /// The number of elements in the input sequence. - public static long LongCount([NotNull] this IQueryable source) + public static long LongCount(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_longCount, source); } @@ -1241,11 +1240,11 @@ public static long LongCount([NotNull] this IQueryable source) /// /// The number of elements in the specified sequence that satisfies a condition. [PublicAPI] - public static long LongCount([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static long LongCount(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -1254,7 +1253,7 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] Parsing } /// - public static long LongCount([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static long LongCount(this IQueryable source, string predicate, params object?[] args) { return LongCount(source, ParsingConfig.Default, predicate, args); } @@ -1265,10 +1264,10 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] string /// The that contains the elements to be counted. /// A cached Lambda Expression. /// The number of elements in the specified sequence that satisfies a condition. - public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static long LongCount(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_longCountPredicate, source, lambda); } @@ -1291,9 +1290,9 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaE /// /// The max element in the sequence. [PublicAPI] - public static object Max([NotNull] this IQueryable source) + public static object Max(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_max, source); } @@ -1313,11 +1312,11 @@ public static object Max([NotNull] this IQueryable source) /// /// The max element in the sequence. [PublicAPI] - public static object Max([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Max(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args); @@ -1327,7 +1326,7 @@ public static object Max([NotNull] this IQueryable source, [NotNull] ParsingConf /// [PublicAPI] - public static object Max([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static object Max(this IQueryable source, string predicate, params object?[] args) { return Max(source, ParsingConfig.Default, predicate, args); } @@ -1339,9 +1338,9 @@ public static object Max([NotNull] this IQueryable source, [NotNull] string pred /// A Lambda Expression. /// The max element in the sequence. [PublicAPI] - public static object Max([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Max(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_maxPredicate, source, lambda); } #endregion Max @@ -1363,9 +1362,9 @@ public static object Max([NotNull] this IQueryable source, [NotNull] LambdaExpre /// /// The min element in the sequence. [PublicAPI] - public static object Min([NotNull] this IQueryable source) + public static object Min(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_min, source); } @@ -1385,11 +1384,11 @@ public static object Min([NotNull] this IQueryable source) /// /// The min element in the sequence. [PublicAPI] - public static object Min([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Min(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args); @@ -1399,7 +1398,7 @@ public static object Min([NotNull] this IQueryable source, [NotNull] ParsingConf /// [PublicAPI] - public static object Min([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static object Min(this IQueryable source, string predicate, params object?[] args) { return Min(source, ParsingConfig.Default, predicate, args); } @@ -1411,9 +1410,9 @@ public static object Min([NotNull] this IQueryable source, [NotNull] string pred /// A Lambda Expression. /// The min element in the sequence. [PublicAPI] - public static object Min([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Min(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_minPredicate, source, lambda); } #endregion Min @@ -1427,12 +1426,12 @@ public static object Min([NotNull] this IQueryable source, [NotNull] LambdaExpre /// An whose elements to filter. /// The type to filter the elements of the sequence on. /// A collection that contains the elements from source that have the type. - public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Type type) + public static IQueryable OfType(this IQueryable source, Type type) { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + Check.NotNull(source); + Check.NotNull(type); - var optimized = OptimizeExpression(Expression.Call(null, _ofType.MakeGenericMethod(new Type[] { type }), new Expression[] { source.Expression })); + var optimized = OptimizeExpression(Expression.Call(null, _ofType.MakeGenericMethod(type), new[] { source.Expression })); return source.Provider.CreateQuery(optimized); } @@ -1444,14 +1443,14 @@ public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Type /// The . /// The type to filter the elements of the sequence on. /// A collection that contains the elements from source that have the type. - public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName) + public static IQueryable OfType(this IQueryable source, ParsingConfig config, string typeName) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(typeName, nameof(typeName)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(typeName); var finder = new TypeFinder(config, new KeywordsHelper(config)); - Type type = finder.FindTypeByName(typeName, null, true); + Type type = finder.FindTypeByName(typeName, null, true)!; return OfType(source, type); } @@ -1462,7 +1461,7 @@ public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Pars /// An whose elements to filter. /// The type to filter the elements of the sequence on. /// A collection that contains the elements from source that have the type. - public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] string typeName) + public static IQueryable OfType(this IQueryable source, string typeName) { return OfType(source, ParsingConfig.Default, typeName); } @@ -1487,13 +1486,13 @@ public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] stri /// ]]> /// /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object?[] args) { return (IOrderedQueryable)OrderBy((IQueryable)source, config, ordering, args); } /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, args); } @@ -1508,9 +1507,9 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { - return (IOrderedQueryable)InternalOrderBy((IQueryable)source, config, ordering, comparer, args); + return (IOrderedQueryable)InternalOrderBy(source, config, ordering, comparer, args); } /// @@ -1522,7 +1521,7 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -1542,11 +1541,11 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// var resultMultiple = queryable.OrderBy("NumberProperty, StringProperty DESC"); /// /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object?[] args) { - if (args.Length > 0 && args[0] != null && args[0].GetType().GetInterfaces().Any(i => i.Name.Contains("IComparer`1"))) + if (args.Length > 0 && args[0] != null && args[0]!.GetType().GetInterfaces().Any(i => i.Name.Contains("IComparer`1"))) { - return InternalOrderBy(source, ParsingConfig.Default, ordering, args[0], args); + return InternalOrderBy(source, ParsingConfig.Default, ordering, args[0]!, args); } return InternalOrderBy(source, config, ordering, null, args); @@ -1561,15 +1560,15 @@ public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNu /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { return InternalOrderBy(source, config, ordering, comparer, args); } - internal static IOrderedQueryable InternalOrderBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, object comparer, params object[] args) + internal static IOrderedQueryable InternalOrderBy(IQueryable source, ParsingConfig config, string ordering, object? comparer, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(ordering, nameof(ordering)); ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(source.ElementType, string.Empty, config.RenameEmptyParameterExpressionNames) }; @@ -1619,13 +1618,13 @@ internal static IOrderedQueryable InternalOrderBy([NotNull] IQueryable source, [ } /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, args); } /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -1640,9 +1639,9 @@ public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNu /// The page to return. /// The number of elements per page. /// A that contains the paged elements. - public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize) + public static IQueryable Page(this IQueryable source, int page, int pageSize) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); @@ -1657,9 +1656,9 @@ public static IQueryable Page([NotNull] this IQueryable source, int page, int pa /// The page to return. /// The number of elements per page. /// A that contains the paged elements. - public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize) + public static IQueryable Page(this IQueryable source, int page, int pageSize) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); @@ -1674,9 +1673,9 @@ public static IQueryable Page([NotNull] this IQueryableThe number of elements per page. /// If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq `Count()`. /// PagedResult - public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize, int? rowCount = null) + public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); Check.Condition(rowCount, rc => rc == null || rc >= 0, nameof(rowCount)); @@ -1703,9 +1702,9 @@ public static PagedResult PageResult([NotNull] this IQueryable source, int page, /// The number of elements per page. /// If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq `Count()`. /// PagedResult{TSource} - public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize, int? rowCount = null) + public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); Check.Condition(rowCount, rc => rc == null || rc >= 0, nameof(rowCount)); @@ -1730,9 +1729,9 @@ public static PagedResult PageResult([NotNull] this IQueryable /// /// A sequence of values to reverse. /// A whose elements correspond to those of the input sequence in reverse order. - public static IQueryable Reverse([NotNull] this IQueryable source) + public static IQueryable Reverse(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Queryable.Reverse((IQueryable)source); } @@ -1753,13 +1752,13 @@ public static IQueryable Reverse([NotNull] this IQueryable source) /// var dynamicObject = queryable.Select("new (StringProperty1, StringProperty2 as OtherStringPropertyName)"); /// /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, selector, args); var optimized = OptimizeExpression(Expression.Call( @@ -1772,7 +1771,7 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Pars } /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, string selector, params object?[] args) { return Select(source, ParsingConfig.Default, selector, args); } @@ -1794,13 +1793,13 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] stri /// ]]> /// /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(TResult), selector, args); var optimized = OptimizeExpression(Expression.Call( @@ -1812,7 +1811,7 @@ public static IQueryable Select([NotNull] this IQueryable sour } /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, string selector, params object?[] args) { return Select(source, ParsingConfig.Default, selector, args); } @@ -1832,14 +1831,14 @@ public static IQueryable Select([NotNull] this IQueryable sour /// var users = queryable.Select(typeof(User), "new (Username, Pwd as Password)"); /// /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(resultType, nameof(resultType)); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, resultType, selector, args); var optimized = OptimizeExpression(Expression.Call( @@ -1851,7 +1850,7 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Pars } /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, Type resultType, string selector, params object?[] args) { return Select(source, ParsingConfig.Default, resultType, selector, args); } @@ -1872,13 +1871,13 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Type /// var roles = users.SelectMany("Roles"); /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { return SelectManyInternal(source, config, null, selector, args); } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, string selector, params object?[] args) { return SelectMany(source, ParsingConfig.Default, selector, args); } @@ -1897,10 +1896,10 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] /// var permissions = users.SelectMany(typeof(Permission), "Roles.SelectMany(Permissions)"); /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(resultType, nameof(resultType)); Check.NotEmpty(selector, nameof(selector)); @@ -1908,14 +1907,14 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, Type resultType, string selector, params object?[] args) { return SelectMany(source, ParsingConfig.Default, resultType, selector, args); } - private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args) + private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig config, Type? resultType, string selector, params object?[] args) { - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, selector, args); //Extra help to get SelectMany to work from StackOverflow Answer @@ -1969,13 +1968,13 @@ private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig co /// ]]> /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(createParameterCtor, source.ElementType, null, selector, args); //we have to adjust to lambda to return an IEnumerable instead of whatever the actual property is. @@ -1994,7 +1993,7 @@ public static IQueryable SelectMany([NotNull] this IQueryable } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, string selector, params object?[] args) { return SelectMany(source, ParsingConfig.Default, selector, args); } @@ -2023,13 +2022,13 @@ public static IQueryable SelectMany([NotNull] this IQueryable /// ]]> /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string collectionSelector, string resultSelector, object[]? collectionSelectorArgs = null, params object[]? resultSelectorArgs) { return SelectMany(source, collectionSelector, resultSelector, "x", "y", collectionSelectorArgs, resultSelectorArgs); } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, object[]? collectionSelectorArgs = null, params object[]? resultSelectorArgs) { return SelectMany(source, ParsingConfig.Default, collectionSelector, resultSelector, "x", "y", collectionSelectorArgs, resultSelectorArgs); } @@ -2060,16 +2059,24 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] /// ]]> /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) - { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + public static IQueryable SelectMany( + this IQueryable source, + ParsingConfig config, + string collectionSelector, + string resultSelector, + string collectionParameterName, + string resultParameterName, + object?[]? collectionSelectorArgs = null, + params object[]? resultSelectorArgs) + { + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(collectionSelector, nameof(collectionSelector)); Check.NotEmpty(collectionParameterName, nameof(collectionParameterName)); Check.NotEmpty(resultSelector, nameof(resultSelector)); Check.NotEmpty(resultParameterName, nameof(resultParameterName)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression sourceSelectLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, collectionSelector, collectionSelectorArgs); //we have to adjust to lambda to return an IEnumerable instead of whatever the actual property is. @@ -2097,7 +2104,7 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, string collectionParameterName, string resultParameterName, object[]? collectionSelectorArgs = null, params object[]? resultSelectorArgs) { return SelectMany(source, ParsingConfig.Default, collectionSelector, resultSelector, collectionParameterName, resultParameterName, collectionSelectorArgs, resultSelectorArgs); } @@ -2115,12 +2122,12 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] /// A to return the single element of. /// The single element of the input sequence. #if NET35 - public static object Single([NotNull] this IQueryable source) + public static object Single(this IQueryable source) #else - public static dynamic Single([NotNull] this IQueryable source) + public static dynamic Single(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.Single), new[] { source.ElementType }, source.Expression)); return source.Provider.Execute(optimized); @@ -2136,14 +2143,14 @@ public static dynamic Single([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object Single([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Single(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic Single([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic Single(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2153,9 +2160,9 @@ public static dynamic Single([NotNull] this IQueryable source, [NotNull] Parsing /// #if NET35 - public static object Single([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object Single(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic Single([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic Single(this IQueryable source, string predicate, params object?[] args) #endif { return Single(source, ParsingConfig.Default, predicate, args); @@ -2169,12 +2176,12 @@ public static dynamic Single([NotNull] this IQueryable source, [NotNull] string /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object Single([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Single(this IQueryable source, LambdaExpression lambda) #else - public static dynamic Single([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic Single(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_singlePredicate, source, lambda); } @@ -2186,15 +2193,15 @@ public static dynamic Single([NotNull] this IQueryable source, [NotNull] LambdaE /// A to return the single element of. /// The single element of the input sequence, or default if the sequence contains no elements. #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source) + public static object SingleOrDefault(this IQueryable source) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source) + public static dynamic SingleOrDefault(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.SingleOrDefault), new[] { source.ElementType }, source.Expression)); - return source.Provider.Execute(optimized); + return source.Provider.Execute(optimized)!; } /// @@ -2207,14 +2214,14 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object SingleOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic SingleOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2224,9 +2231,9 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull /// #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object SingleOrDefault(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic SingleOrDefault(this IQueryable source, string predicate, params object?[] args) #endif { return SingleOrDefault(source, ParsingConfig.Default, predicate, args); @@ -2240,13 +2247,13 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object SingleOrDefault(this IQueryable source, LambdaExpression lambda) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic SingleOrDefault(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_singleDefaultPredicate, source, lambda); } @@ -2261,9 +2268,9 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull /// A to return elements from. /// The number of elements to skip before returning the remaining elements. /// A that contains elements that occur after the specified index in the input sequence. - public static IQueryable Skip([NotNull] this IQueryable source, int count) + public static IQueryable Skip(this IQueryable source, int count) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(count, x => x >= 0, nameof(count)); //no need to skip if count is zero @@ -2292,10 +2299,10 @@ public static IQueryable Skip([NotNull] this IQueryable source, int count) /// /// /// An that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate. - public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable SkipWhile(this IQueryable source, ParsingConfig config, string predicate, params object[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(predicate, nameof(predicate)); bool createParameterCtor = SupportsLinqToObjects(config, source); @@ -2305,7 +2312,7 @@ public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] P } /// - public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable SkipWhile(this IQueryable source, string predicate, params object[]? args) { return SkipWhile(source, ParsingConfig.Default, predicate, args); } @@ -2325,9 +2332,9 @@ public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] s /// /// The sum of the values in the sequence. [PublicAPI] - public static object Sum([NotNull] this IQueryable source) + public static object Sum(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var sum = QueryableMethodFinder.GetMethod(nameof(Queryable.Sum), source.ElementType); return Execute(sum, source); @@ -2348,11 +2355,11 @@ public static object Sum([NotNull] this IQueryable source) /// /// The sum of the values in the sequence. [PublicAPI] - public static object Sum([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Sum(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2364,7 +2371,7 @@ public static object Sum([NotNull] this IQueryable source, [NotNull] ParsingConf /// [PublicAPI] - public static object Sum([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static object Sum(this IQueryable source, string predicate, params object?[] args) { return Sum(source, ParsingConfig.Default, predicate, args); } @@ -2376,10 +2383,10 @@ public static object Sum([NotNull] this IQueryable source, [NotNull] string pred /// A Lambda Expression. /// The sum of the values in the sequence. [PublicAPI] - public static object Sum([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Sum(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); var sumSelector = QueryableMethodFinder.GetMethod(nameof(Queryable.Sum), lambda.GetReturnType(), 1); @@ -2395,9 +2402,9 @@ public static object Sum([NotNull] this IQueryable source, [NotNull] LambdaExpre /// The sequence to return elements from. /// The number of elements to return. /// A that contains the specified number of elements from the start of source. - public static IQueryable Take([NotNull] this IQueryable source, int count) + public static IQueryable Take(this IQueryable source, int count) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(count, x => x >= 0, nameof(count)); return CreateQuery(_take, source, Expression.Constant(count)); @@ -2422,10 +2429,10 @@ public static IQueryable Take([NotNull] this IQueryable source, int count) /// /// /// An that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes. - public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable TakeWhile(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(predicate, nameof(predicate)); bool createParameterCtor = SupportsLinqToObjects(config, source); @@ -2435,7 +2442,7 @@ public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] P } /// - public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable TakeWhile(this IQueryable source, string predicate, params object?[] args) { return TakeWhile(source, ParsingConfig.Default, predicate, args); } @@ -2462,13 +2469,13 @@ public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] s /// ]]> /// /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object?[] args) { return (IOrderedQueryable)ThenBy((IOrderedQueryable)source, config, ordering, args); } /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, args); } @@ -2483,9 +2490,9 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { - return (IOrderedQueryable)InternalThenBy((IOrderedQueryable)source, config, ordering, comparer, args); + return (IOrderedQueryable)InternalThenBy(source, config, ordering, comparer, args); } /// @@ -2497,7 +2504,7 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -2518,7 +2525,7 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// var resultMultiple = result.OrderBy("NumberProperty, StringProperty DESC"); /// /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object?[] args) { return InternalThenBy(source, config, ordering, null, args); } @@ -2532,15 +2539,15 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { return InternalThenBy(source, config, ordering, comparer, args); } - internal static IOrderedQueryable InternalThenBy([NotNull] IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + internal static IOrderedQueryable InternalThenBy(IOrderedQueryable source, ParsingConfig config, string ordering, IComparer? comparer, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(ordering, nameof(ordering)); ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(source.ElementType, string.Empty, config.RenameEmptyParameterExpressionNames) }; @@ -2574,13 +2581,13 @@ internal static IOrderedQueryable InternalThenBy([NotNull] IOrderedQueryable sou } /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, args); } /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -2606,13 +2613,13 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, /// var result5 = queryable.Where("StringProperty = @0", "abc"); /// /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { return (IQueryable)Where((IQueryable)source, config, predicate, args); } - /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + /// + public static IQueryable Where(this IQueryable source, string predicate, params object?[] args) { return Where(source, ParsingConfig.Default, predicate, args); } @@ -2634,11 +2641,11 @@ public static IQueryable Where([NotNull] this IQueryable /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2648,7 +2655,7 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] Parsi } /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static IQueryable Where(this IQueryable source, string predicate, params object?[] args) { return Where(source, ParsingConfig.Default, predicate, args); } @@ -2659,17 +2666,17 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] strin /// A to filter. /// A cached Lambda Expression. /// A that contains elements from the input sequence that satisfy the condition specified by LambdaExpression. - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static IQueryable Where(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.Where), new[] { source.ElementType }, source.Expression, Expression.Quote(lambda))); return source.Provider.CreateQuery(optimized); } /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static IQueryable Where(this IQueryable source, LambdaExpression lambda) { return (IQueryable)Where((IQueryable)source, lambda); } @@ -2681,7 +2688,7 @@ private static bool SupportsLinqToObjects(ParsingConfig config, IQueryable query return config.QueryableAnalyzer.SupportsLinqToObjects(query); } - private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object[] args) + private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object?[] args) { Type outerSelectorReturnType = outerSelectorLambda.Body.Type; Type innerSelectorReturnType = innerSelectorLambda.Body.Type; @@ -2740,7 +2747,7 @@ private static object Execute(MethodInfo operatorMethodInfo, IQueryable source) } var optimized = OptimizeExpression(Expression.Call(null, operatorMethodInfo, source.Expression)); - return source.Provider.Execute(optimized); + return source.Provider.Execute(optimized)!; } private static TResult Execute(MethodInfo operatorMethodInfo, IQueryable source) @@ -2765,7 +2772,7 @@ private static object Execute(MethodInfo operatorMethodInfo, IQueryable source, : operatorMethodInfo.MakeGenericMethod(source.ElementType); var optimized = OptimizeExpression(Expression.Call(null, operatorMethodInfo, source.Expression, expression)); - return source.Provider.Execute(optimized); + return source.Provider.Execute(optimized)!; } private static TResult Execute(MethodInfo operatorMethodInfo, IQueryable source, LambdaExpression expression) @@ -2786,4 +2793,4 @@ private static TResult Execute(MethodInfo operatorMethodInfo, IQueryabl #endregion Private Helpers } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs index eb0ae3a7..8cc57e0b 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs @@ -1,4 +1,6 @@ -using System.Collections; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System.Collections; using System.Text.RegularExpressions; using JetBrains.Annotations; @@ -12,7 +14,7 @@ namespace System.Linq.Dynamic.Core /// public static class DynamicQueryableWithFormattableStringExtensions { - private static Regex ReplaceArgumentsRegex = new Regex(@"{(\d+)}", RegexOptions.Compiled); + private static readonly Regex ReplaceArgumentsRegex = new(@"{(\d+)}", RegexOptions.Compiled); public static IQueryable WhereInterpolated([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] FormattableString predicate) { @@ -426,4 +428,5 @@ private static string ParseFormattableString(FormattableString predicate, out ob } } #endif -} \ No newline at end of file +} +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/GroupResult.cs b/src/System.Linq.Dynamic.Core/GroupResult.cs index bd8aa556..591911da 100644 --- a/src/System.Linq.Dynamic.Core/GroupResult.cs +++ b/src/System.Linq.Dynamic.Core/GroupResult.cs @@ -13,9 +13,9 @@ public class GroupResult /// The key value of the group. /// #if NET35 || SILVERLIGHT - public object Key { get; internal set; } + public object Key { get; internal set; } = null!; #else - public dynamic Key { get; internal set; } + public dynamic Key { get; internal set; } = null!; #endif /// @@ -31,7 +31,7 @@ public class GroupResult /// /// The resulting subgroups in the group. /// - public IEnumerable Subgroups { get; internal set; } + public IEnumerable? Subgroups { get; internal set; } /// /// Returns a showing the key of the group and the number of items in the group. diff --git a/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs b/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs index 530abf1b..163f5121 100644 --- a/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs +++ b/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs @@ -1,18 +1,15 @@ -using JetBrains.Annotations; +namespace System.Linq.Dynamic.Core; -namespace System.Linq.Dynamic.Core +/// +/// Interface for QueryableAnalyzer. +/// +public interface IQueryableAnalyzer { /// - /// Interface for QueryableAnalyzer. + /// Determines whether the specified query (and provider) supports LinqToObjects. /// - public interface IQueryableAnalyzer - { - /// - /// Determines whether the specified query (and provider) supports LinqToObjects. - /// - /// The query to check. - /// The provider to check (can be null). - /// true/false - bool SupportsLinqToObjects([NotNull] IQueryable query, [CanBeNull] IQueryProvider provider = null); - } -} + /// The query to check. + /// The provider to check (can be null). + /// true/false + bool SupportsLinqToObjects(IQueryable query, IQueryProvider? provider = null); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs b/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs index 0c42bd5c..974a0c78 100644 --- a/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs @@ -1,57 +1,27 @@ using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +internal static class ParameterExpressionHelper { - internal static class ParameterExpressionHelper + public static ParameterExpression CreateParameterExpression(Type type, string name, bool renameEmpty = false) { - public static ParameterExpression CreateParameterExpression(Type type, string name, bool renameEmpty = false) + string paramName = name; + if (renameEmpty && paramName.IsNullOrWhiteSpace()) { - string paramName = name; - if (renameEmpty && IsNullOrWhiteSpace(paramName)) - { - paramName = GenerateRandomWord(); - } - return Expression.Parameter(type, paramName); + paramName = GenerateRandomWord(); } - /// - /// Indicates whether a specified string is null, empty, or consists only of white-space - /// characters. - /// - /// Recreates the same functionality as System.String.IsNullOrWhiteSpace but included here - /// for compatibility with net35. - /// - /// - /// The string to test. - /// - /// - /// true if the value parameter is null or System.String.Empty, or if value consists - /// exclusively of white-space characters. - /// - internal static bool IsNullOrWhiteSpace(string value) - { - if (value == null) - { - return true; - } - for (int i = 0; i < value.Length; i++) - { - if (!char.IsWhiteSpace(value[i])) - { - return false; - } - } - return true; - } + return Expression.Parameter(type, paramName); + } - /// - /// Generates a random 16 character word derived from a Guid value. - /// - internal static string GenerateRandomWord() - { - const int wordLength = 16; - const int diff = 'A' - '0'; - return string.Concat(Guid.NewGuid().ToString(@"N").Select(c => (char)(c + diff)).Take(wordLength)).ToLower(); - } + /// + /// Generates a random 16 character word derived from a Guid value. + /// + internal static string GenerateRandomWord() + { + const int wordLength = 16; + const int diff = 'A' - '0'; + return string.Concat(Guid.NewGuid().ToString(@"N").Select(c => (char)(c + diff)).Take(wordLength)).ToLower(); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs index 3c0efe7f..5b651651 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs @@ -5,10 +5,10 @@ namespace System.Linq.Dynamic.Core.Parser { internal static class ConstantExpressionHelper { - private static readonly ConcurrentDictionary Expressions = new ConcurrentDictionary(); - private static readonly ConcurrentDictionary Literals = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary Expressions = new(); + private static readonly ConcurrentDictionary Literals = new(); - public static bool TryGetText(Expression expression, out string text) + public static bool TryGetText(Expression expression, out string? text) { return Literals.TryGetValue(expression, out text); } @@ -26,4 +26,4 @@ public static Expression CreateLiteral(object value, string text) return Expressions[value]; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/Constants.cs b/src/System.Linq.Dynamic.Core/Parser/Constants.cs index 86555261..d28c6a50 100644 --- a/src/System.Linq.Dynamic.Core/Parser/Constants.cs +++ b/src/System.Linq.Dynamic.Core/Parser/Constants.cs @@ -1,12 +1,11 @@ using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal static class Constants { - internal static class Constants + public static bool IsNull(Expression exp) { - public static bool IsNull(Expression exp) - { - return exp is ConstantExpression cExp && cExp.Value == null; - } + return exp is ConstantExpression { Value: null }; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs index 3074a326..2a8dc419 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs @@ -4,7 +4,6 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; -using JetBrains.Annotations; namespace System.Linq.Dynamic.Core.Parser { @@ -13,11 +12,9 @@ internal class ExpressionHelper : IExpressionHelper private readonly IConstantExpressionWrapper _constantExpressionWrapper = new ConstantExpressionWrapper(); private readonly ParsingConfig _parsingConfig; - internal ExpressionHelper([NotNull] ParsingConfig parsingConfig) + internal ExpressionHelper(ParsingConfig parsingConfig) { - Check.NotNull(parsingConfig, nameof(parsingConfig)); - - _parsingConfig = parsingConfig; + _parsingConfig = Check.NotNull(parsingConfig); } public void WrapConstantExpression(ref Expression argument) @@ -187,16 +184,16 @@ public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression ri if (rightType == typeof(string) && right.NodeType == ExpressionType.Constant) { - right = OptimizeStringForEqualityIfPossible((string)((ConstantExpression)right).Value, leftType) ?? right; + right = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)right).Value, leftType) ?? right; } if (leftType == typeof(string) && left.NodeType == ExpressionType.Constant) { - left = OptimizeStringForEqualityIfPossible((string)((ConstantExpression)left).Value, rightType) ?? left; + left = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)left).Value, rightType) ?? left; } } - public Expression OptimizeStringForEqualityIfPossible(string text, Type type) + public Expression? OptimizeStringForEqualityIfPossible(string? text, Type type) { if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) { @@ -243,7 +240,7 @@ private MethodInfo GetStaticMethod(string methodName, Expression left, Expressio var methodInfo = left.Type.GetMethod(methodName, new[] { left.Type, right.Type }); if (methodInfo == null) { - methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type }); + methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type })!; } return methodInfo; @@ -292,7 +289,7 @@ public bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, boo return true; } - public bool ExpressionQualifiesForNullPropagation(Expression expression) + public bool ExpressionQualifiesForNullPropagation(Expression? expression) { return expression is MemberExpression || @@ -310,7 +307,7 @@ public Expression GenerateDefaultExpression(Type type) #endif } - private Expression GetMemberExpression(Expression expression) + private Expression? GetMemberExpression(Expression? expression) { if (ExpressionQualifiesForNullPropagation(expression)) { @@ -335,7 +332,7 @@ private Expression GetMemberExpression(Expression expression) private List CollectExpressions(bool addSelf, Expression sourceExpression) { - Expression expression = GetMemberExpression(sourceExpression); + Expression? expression = GetMemberExpression(sourceExpression); var list = new List(); @@ -347,6 +344,7 @@ private List CollectExpressions(bool addSelf, Expression sourceExpre list.Add(sourceExpression); break; + // ReSharper disable once RedundantEmptySwitchSection default: break; } @@ -379,14 +377,14 @@ private List CollectExpressions(bool addSelf, Expression sourceExpre if (expressionRecognized && ExpressionQualifiesForNullPropagation(expression)) { - list.Add(expression); + list.Add(expression!); } } while (expressionRecognized); return list; } - private static Expression GetMethodCallExpression(MethodCallExpression methodCallExpression) + private static Expression? GetMethodCallExpression(MethodCallExpression methodCallExpression) { if (methodCallExpression.Object != null) { @@ -398,9 +396,9 @@ private static Expression GetMethodCallExpression(MethodCallExpression methodCal return methodCallExpression.Arguments.FirstOrDefault(); } - private static Expression GetUnaryExpression(UnaryExpression unaryExpression) + private static Expression? GetUnaryExpression(UnaryExpression? unaryExpression) { - return unaryExpression.Operand; + return unaryExpression?.Operand; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 0cca1657..ace1822f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -10,7 +10,6 @@ using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; using System.Reflection; -using JetBrains.Annotations; namespace System.Linq.Dynamic.Core.Parser { @@ -19,10 +18,10 @@ namespace System.Linq.Dynamic.Core.Parser /// public class ExpressionParser { - static readonly string methodOrderBy = nameof(Queryable.OrderBy); - static readonly string methodOrderByDescending = nameof(Queryable.OrderByDescending); - static readonly string methodThenBy = nameof(Queryable.ThenBy); - static readonly string methodThenByDescending = nameof(Queryable.ThenByDescending); + private static readonly string methodOrderBy = nameof(Queryable.OrderBy); + private static readonly string methodOrderByDescending = nameof(Queryable.OrderByDescending); + private static readonly string methodThenBy = nameof(Queryable.ThenBy); + private static readonly string methodThenByDescending = nameof(Queryable.ThenByDescending); private readonly ParsingConfig _parsingConfig; private readonly MethodFinder _methodFinder; @@ -32,14 +31,14 @@ public class ExpressionParser private readonly IExpressionHelper _expressionHelper; private readonly ITypeFinder _typeFinder; private readonly ITypeConverterFactory _typeConverterFactory; - private readonly Dictionary _internals; - private readonly Dictionary _symbols; - - private IDictionary _externals; - private ParameterExpression _it; - private ParameterExpression _parent; - private ParameterExpression _root; - private Type _resultType; + private readonly Dictionary _internals = new(); + private readonly Dictionary _symbols; + + private IDictionary? _externals; + private ParameterExpression? _it; + private ParameterExpression? _parent; + private ParameterExpression? _root; + private Type? _resultType; private bool _createParameterCtor; /// @@ -63,12 +62,20 @@ public class ExpressionParser /// The expression. /// The values. /// The parsing configuration. - public ExpressionParser([CanBeNull] ParameterExpression[] parameters, [NotNull] string expression, [CanBeNull] object[] values, [CanBeNull] ParsingConfig parsingConfig) + public ExpressionParser(ParameterExpression[]? parameters, string expression, object?[]? values, ParsingConfig? parsingConfig) { Check.NotEmpty(expression, nameof(expression)); - _symbols = new Dictionary(parsingConfig != null && parsingConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); - _internals = new Dictionary(); + _symbols = new Dictionary(parsingConfig is { IsCaseSensitive: true } ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); + _parsingConfig = parsingConfig ?? ParsingConfig.Default; + + _keywordsHelper = new KeywordsHelper(_parsingConfig); + _textParser = new TextParser(_parsingConfig, expression); + _numberParser = new NumberParser(parsingConfig); + _methodFinder = new MethodFinder(_parsingConfig); + _expressionHelper = new ExpressionHelper(_parsingConfig); + _typeFinder = new TypeFinder(_parsingConfig, _keywordsHelper); + _typeConverterFactory = new TypeConverterFactory(_parsingConfig); if (parameters != null) { @@ -79,19 +86,9 @@ public ExpressionParser([CanBeNull] ParameterExpression[] parameters, [NotNull] { ProcessValues(values); } - - _parsingConfig = parsingConfig ?? ParsingConfig.Default; - - _keywordsHelper = new KeywordsHelper(_parsingConfig); - _textParser = new TextParser(_parsingConfig, expression); - _numberParser = new NumberParser(parsingConfig); - _methodFinder = new MethodFinder(_parsingConfig); - _expressionHelper = new ExpressionHelper(_parsingConfig); - _typeFinder = new TypeFinder(_parsingConfig, _keywordsHelper); - _typeConverterFactory = new TypeConverterFactory(_parsingConfig); } - void ProcessParameters(ParameterExpression[] parameters) + private void ProcessParameters(ParameterExpression[] parameters) { foreach (ParameterExpression pe in parameters.Where(p => !string.IsNullOrEmpty(p.Name))) { @@ -111,12 +108,12 @@ void ProcessParameters(ParameterExpression[] parameters) } } - void ProcessValues(object[] values) + private void ProcessValues(object?[] values) { for (int i = 0; i < values.Length; i++) { - object value = values[i]; - IDictionary externals; + object? value = values[i]; + IDictionary? externals; if (i == values.Length - 1 && (externals = value as IDictionary) != null) { @@ -129,7 +126,7 @@ void ProcessValues(object[] values) } } - private void AddSymbol(string name, object value) + private void AddSymbol(string name, object? value) { if (_symbols.ContainsKey(name)) { @@ -145,13 +142,13 @@ private void AddSymbol(string name, object value) /// Type of the result. /// if set to true [create parameter ctor]. /// Expression - public Expression Parse([CanBeNull] Type resultType, bool createParameterCtor = true) + public Expression Parse(Type? resultType, bool createParameterCtor = true) { _resultType = resultType; _createParameterCtor = createParameterCtor; int exprPos = _textParser.CurrentToken.Pos; - Expression expr = ParseConditionalOperator(); + Expression? expr = ParseConditionalOperator(); if (resultType != null) { @@ -210,7 +207,7 @@ internal IList ParseOrdering(bool forceThenBy = false) #pragma warning restore 0219 // ?: operator - Expression ParseConditionalOperator() + private Expression ParseConditionalOperator() { int errorPos = _textParser.CurrentToken.Pos; Expression expr = ParseNullCoalescingOperator(); @@ -227,7 +224,7 @@ Expression ParseConditionalOperator() } // ?? (null-coalescing) operator - Expression ParseNullCoalescingOperator() + private Expression ParseNullCoalescingOperator() { Expression expr = ParseLambdaOperator(); if (_textParser.CurrentToken.Id == TokenId.NullCoalescing) @@ -240,10 +237,10 @@ Expression ParseNullCoalescingOperator() } // => operator - Added Support for projection operator - Expression ParseLambdaOperator() + private Expression ParseLambdaOperator() { Expression expr = ParseOrOperator(); - if (_textParser.CurrentToken.Id == TokenId.Lambda && _it.Type == expr.Type) + if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == expr.Type) { _textParser.NextToken(); if (_textParser.CurrentToken.Id == TokenId.Identifier || _textParser.CurrentToken.Id == TokenId.OpenParen) @@ -260,7 +257,7 @@ Expression ParseLambdaOperator() // - || // - Or // - OrElse - Expression ParseOrOperator() + private Expression ParseOrOperator() { Expression left = ParseAndOperator(); while (_textParser.CurrentToken.Id == TokenId.DoubleBar) @@ -278,7 +275,7 @@ Expression ParseOrOperator() // - && // - And // - AndAlso - Expression ParseAndOperator() + private Expression ParseAndOperator() { Expression left = ParseIn(); while (_textParser.CurrentToken.Id == TokenId.DoubleAmpersand) @@ -295,7 +292,7 @@ Expression ParseAndOperator() // in operator for literals - example: "x in (1,2,3,4)" // in operator to mimic contains - example: "x in @0", compare to @0.Contains(x) // Adapted from ticket submitted by github user mlewis9548 - Expression ParseIn() + private Expression ParseIn() { Expression left = ParseLogicalAndOrOperator(); Expression accumulate = left; @@ -315,9 +312,9 @@ Expression ParseIn() Expression right = ParseUnary(); // if the identifier is an Enum, try to convert the right-side also to an Enum. - if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression) + if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression constantExpression) { - right = ParseEnumToConstantExpression(op.Pos, left.Type, right as ConstantExpression); + right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpression); } // else, check for direct type match @@ -355,8 +352,8 @@ Expression ParseIn() var args = new[] { left }; - Expression nullExpressionReference = null; - if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out MethodBase containsSignature) != 1) + Expression? nullExpressionReference = null; + if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out var containsSignature) != 1) { throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray())); } @@ -365,7 +362,7 @@ Expression ParseIn() args = new[] { right, left }; - accumulate = Expression.Call(typeof(Enumerable), containsSignature.Name, typeArgs, args); + accumulate = Expression.Call(typeof(Enumerable), containsSignature!.Name, typeArgs, args); } else { @@ -377,7 +374,7 @@ Expression ParseIn() } // &, | bitwise operators - Expression ParseLogicalAndOrOperator() + private Expression ParseLogicalAndOrOperator() { Expression left = ParseComparisonOperator(); while (_textParser.CurrentToken.Id == TokenId.Ampersand || _textParser.CurrentToken.Id == TokenId.Bar) @@ -399,8 +396,7 @@ Expression ParseLogicalAndOrOperator() switch (op.Id) { case TokenId.Ampersand: - int parseValue; - if (left.Type == typeof(string) && left.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)left).Value, out parseValue) && TypeHelper.IsNumericType(right.Type)) + if (left.Type == typeof(string) && left.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)left).Value, out var parseValue) && TypeHelper.IsNumericType(right.Type)) { left = Expression.Constant(parseValue); } @@ -432,7 +428,7 @@ Expression ParseLogicalAndOrOperator() } // =, ==, !=, <>, >, >=, <, <= operators - Expression ParseComparisonOperator() + private Expression ParseComparisonOperator() { Expression left = ParseShiftOperator(); while (_textParser.CurrentToken.Id == TokenId.Equal || _textParser.CurrentToken.Id == TokenId.DoubleEqual || @@ -440,7 +436,7 @@ Expression ParseComparisonOperator() _textParser.CurrentToken.Id == TokenId.GreaterThan || _textParser.CurrentToken.Id == TokenId.GreaterThanEqual || _textParser.CurrentToken.Id == TokenId.LessThan || _textParser.CurrentToken.Id == TokenId.LessThanEqual) { - ConstantExpression constantExpr; + ConstantExpression? constantExpr; TypeConverter typeConverter; Token op = _textParser.CurrentToken; _textParser.NextToken(); @@ -470,7 +466,7 @@ Expression ParseComparisonOperator() { if (left.Type != right.Type) { - Expression e; + Expression? e; if ((e = _parsingConfig.ExpressionPromoter.Promote(right, left.Type, true, false)) != null) { right = e; @@ -517,7 +513,6 @@ Expression ParseComparisonOperator() } } - if (!typesAreSameAndImplementCorrectInterface) { if ((TypeHelper.IsClass(left.Type) || TypeHelper.IsStruct(left.Type)) && right is ConstantExpression) @@ -623,7 +618,7 @@ private object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExp } // <<, >> operators - Expression ParseShiftOperator() + private Expression ParseShiftOperator() { Expression left = ParseAdditive(); while (_textParser.CurrentToken.Id == TokenId.DoubleLessThan || _textParser.CurrentToken.Id == TokenId.DoubleGreaterThan) @@ -647,7 +642,7 @@ Expression ParseShiftOperator() } // +, - operators - Expression ParseAdditive() + private Expression ParseAdditive() { Expression left = ParseMultiplicative(); while (_textParser.CurrentToken.Id == TokenId.Plus || _textParser.CurrentToken.Id == TokenId.Minus) @@ -678,7 +673,7 @@ Expression ParseAdditive() } // *, /, %, mod operators - Expression ParseMultiplicative() + private Expression ParseMultiplicative() { Expression left = ParseUnary(); while (_textParser.CurrentToken.Id == TokenId.Asterisk || _textParser.CurrentToken.Id == TokenId.Slash || @@ -706,7 +701,7 @@ Expression ParseMultiplicative() } // -, !, not unary operators - Expression ParseUnary() + private Expression ParseUnary() { if (_textParser.CurrentToken.Id == TokenId.Minus || _textParser.CurrentToken.Id == TokenId.Exclamation || TokenIdentifierIs("not")) { @@ -737,7 +732,7 @@ Expression ParseUnary() return ParsePrimary(); } - Expression ParsePrimary() + private Expression ParsePrimary() { Expression expr = ParsePrimaryStart(); _expressionHelper.WrapConstantExpression(ref expr); @@ -765,7 +760,7 @@ Expression ParsePrimary() return expr; } - Expression ParsePrimaryStart() + private Expression ParsePrimaryStart() { switch (_textParser.CurrentToken.Id) { @@ -784,7 +779,7 @@ Expression ParsePrimaryStart() } } - Expression ParseStringLiteral() + private Expression ParseStringLiteral() { _textParser.ValidateToken(TokenId.StringLiteral); @@ -805,7 +800,7 @@ Expression ParseStringLiteral() return ConstantExpressionHelper.CreateLiteral(result, result); } - Expression ParseIntegerLiteral() + private Expression ParseIntegerLiteral() { _textParser.ValidateToken(TokenId.IntegerLiteral); @@ -818,7 +813,7 @@ Expression ParseIntegerLiteral() return constantExpression; } - Expression ParseRealLiteral() + private Expression ParseRealLiteral() { _textParser.ValidateToken(TokenId.RealLiteral); @@ -829,7 +824,7 @@ Expression ParseRealLiteral() return _numberParser.ParseRealLiteral(text, text[text.Length - 1], true); } - Expression ParseParenExpression() + private Expression ParseParenExpression() { _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); _textParser.NextToken(); @@ -839,16 +834,15 @@ Expression ParseParenExpression() return e; } - Expression ParseIdentifier() + private Expression ParseIdentifier() { _textParser.ValidateToken(TokenId.Identifier); - if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object value) && + if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object? value) && // Prioritize property or field over the type !(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null)) { - Type typeValue = value as Type; - if (typeValue != null) + if (value is Type typeValue) { return ParseTypeAccess(typeValue); } @@ -924,7 +918,7 @@ Expression ParseIdentifier() throw ParseError(Res.UnknownIdentifier, _textParser.CurrentToken.Text); } - Expression ParseIt() + private Expression ParseIt() { if (_it == null) { @@ -934,7 +928,7 @@ Expression ParseIt() return _it; } - Expression ParseParent() + private Expression ParseParent() { if (_parent == null) { @@ -944,7 +938,7 @@ Expression ParseParent() return _parent; } - Expression ParseRoot() + private Expression ParseRoot() { if (_root == null) { @@ -955,7 +949,7 @@ Expression ParseRoot() } // isnull(a,b) function - Expression ParseFunctionIsNull() + private Expression ParseFunctionIsNull() { int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); @@ -969,7 +963,7 @@ Expression ParseFunctionIsNull() } // iif(test, ifTrue, ifFalse) function - Expression ParseFunctionIif() + private Expression ParseFunctionIif() { int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); @@ -984,7 +978,7 @@ Expression ParseFunctionIif() } // np(...) function - Expression ParseFunctionNullPropagation() + private Expression ParseFunctionNullPropagation() { int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); @@ -1013,7 +1007,7 @@ Expression ParseFunctionNullPropagation() } // Is(...) function - Expression ParseFunctionIs() + private Expression ParseFunctionIs() { int errorPos = _textParser.CurrentToken.Pos; string functionName = _textParser.CurrentToken.Text; @@ -1031,7 +1025,7 @@ Expression ParseFunctionIs() if (args.Length == 1) { typeArgument = args[0]; - it = _it; + it = _it!; } else { @@ -1043,7 +1037,7 @@ Expression ParseFunctionIs() } // As(...) function - Expression ParseFunctionAs() + private Expression ParseFunctionAs() { int errorPos = _textParser.CurrentToken.Pos; string functionName = _textParser.CurrentToken.Text; @@ -1061,7 +1055,7 @@ Expression ParseFunctionAs() if (args.Length == 1) { typeArgument = args[0]; - it = _it; + it = _it!; } else { @@ -1073,7 +1067,7 @@ Expression ParseFunctionAs() } // Cast(...) function - Expression ParseFunctionCast() + private Expression ParseFunctionCast() { int errorPos = _textParser.CurrentToken.Pos; string functionName = _textParser.CurrentToken.Text; @@ -1091,7 +1085,7 @@ Expression ParseFunctionCast() if (args.Length == 1) { typeArgument = args[0]; - it = _it; + it = _it!; } else { @@ -1102,7 +1096,7 @@ Expression ParseFunctionCast() return Expression.ConvertChecked(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); } - Expression GenerateConditional(Expression test, Expression expressionIfTrue, Expression expressionIfFalse, bool nullPropagating, int errorPos) + private Expression GenerateConditional(Expression test, Expression expressionIfTrue, Expression expressionIfFalse, bool nullPropagating, int errorPos) { if (test.Type != typeof(bool)) { @@ -1181,8 +1175,8 @@ Expression GenerateConditional(Expression test, Expression expressionIfTrue, Exp return Expression.Condition(test, expressionIfTrue, expressionIfFalse); } - Expression expr1As2 = !Constants.IsNull(expressionIfFalse) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfTrue, expressionIfFalse.Type, true, false) : null; - Expression expr2As1 = !Constants.IsNull(expressionIfTrue) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfFalse, expressionIfTrue.Type, true, false) : null; + var expr1As2 = !Constants.IsNull(expressionIfFalse) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfTrue, expressionIfFalse.Type, true, false) : null; + var expr2As1 = !Constants.IsNull(expressionIfTrue) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfFalse, expressionIfTrue.Type, true, false) : null; if (expr1As2 != null && expr2As1 == null) { expressionIfTrue = expr1As2; @@ -1208,7 +1202,7 @@ Expression GenerateConditional(Expression test, Expression expressionIfTrue, Exp } // new (...) function - Expression ParseNew() + private Expression ParseNew() { _textParser.NextToken(); if (_textParser.CurrentToken.Id != TokenId.OpenParen && @@ -1219,7 +1213,7 @@ Expression ParseNew() throw ParseError(Res.OpenParenOrIdentifierExpected); } - Type newType = null; + Type? newType = null; if (_textParser.CurrentToken.Id == TokenId.Identifier) { var newTypeName = _textParser.CurrentToken.Text; @@ -1272,7 +1266,7 @@ Expression ParseNew() Expression expr = ParseConditionalOperator(); if (!arrayInitializer) { - string propName; + string? propName; if (TokenIdentifierIs("as")) { _textParser.NextToken(); @@ -1281,7 +1275,7 @@ Expression ParseNew() } else { - if (!TryGetMemberName(expr, out propName)) + if (!TryGetMemberName(expr, out propName)) // TODO : investigate this { if (expr is MethodCallExpression methodCallExpression && methodCallExpression.Arguments.Count == 1 @@ -1298,7 +1292,10 @@ Expression ParseNew() } } - properties.Add(new DynamicProperty(propName, expr.Type)); + if (!string.IsNullOrEmpty(propName)) + { + properties.Add(new DynamicProperty(propName!, expr.Type)); + } } expressions.Add(expr); @@ -1325,7 +1322,7 @@ Expression ParseNew() return CreateNewExpression(properties, expressions, newType); } - private Expression CreateArrayInitializerExpression(List expressions, Type newType) + private Expression CreateArrayInitializerExpression(List expressions, Type? newType) { if (expressions.Count == 0) { @@ -1340,10 +1337,10 @@ private Expression CreateArrayInitializerExpression(List expressions return Expression.NewArrayInit(expressions.All(expression => expression.Type == expressions[0].Type) ? expressions[0].Type : typeof(object), expressions); } - private Expression CreateNewExpression(List properties, List expressions, Type newType) + private Expression CreateNewExpression(List properties, List expressions, Type? newType) { // http://solutionizing.net/category/linq/ - Type type = newType ?? _resultType; + Type? type = newType ?? _resultType; if (type == null) { @@ -1390,7 +1387,7 @@ private Expression CreateNewExpression(List properties, List constructorParameters .Any(cp => cp.Name == p.Name && (cp.ParameterType == p.Type || p.Type == Nullable.GetUnderlyingType(cp.ParameterType)))); - var expressionsPromoted = new List(); + var expressionsPromoted = new List(); // Loop all expressions and promote if needed for (int i = 0; i < constructorParameters.Length; i++) @@ -1434,7 +1431,7 @@ private Expression CreateNewExpression(List properties, List properties, List properties, List !c.GetParameters().Any(p => p.ParameterType.GetTypeInfo().IsPointer)) .ToArray(); - switch (_methodFinder.FindBestMethodBasedOnArguments(constructorsWithOutPointerArguments, ref args, out MethodBase method)) + switch (_methodFinder.FindBestMethodBasedOnArguments(constructorsWithOutPointerArguments, ref args, out var method)) { case 0: if (args.Length == 1 && TryGenerateConversion(args[0], type, out generatedExpression)) { - return generatedExpression; + return generatedExpression!; } throw ParseError(errorPos, Res.NoMatchingConstructor, TypeHelper.GetTypeName(type)); case 1: - return Expression.New((ConstructorInfo)method, args); + return Expression.New((ConstructorInfo)method!, args); default: throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, TypeHelper.GetTypeName(type)); @@ -1547,7 +1549,7 @@ Expression ParseTypeAccess(Type type) return ParseMemberAccess(type, null); } - private bool TryGenerateConversion(Expression sourceExpression, Type type, out Expression expression) + private bool TryGenerateConversion(Expression sourceExpression, Type type, out Expression? expression) { Type exprType = sourceExpression.Type; if (exprType == type) @@ -1583,6 +1585,7 @@ private bool TryGenerateConversion(Expression sourceExpression, Type type, out E string text = (string)((ConstantExpression)sourceExpression).Value; var typeConvertor = _typeConverterFactory.GetConverter(type); + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (typeConvertor != null && typeConvertor.CanConvertFrom(typeof(string))) { var value = typeConvertor.ConvertFromInvariantString(text); @@ -1603,7 +1606,7 @@ private bool TryGenerateConversion(Expression sourceExpression, Type type, out E return false; } - Expression ParseMemberAccess(Type type, Expression expression) + private Expression ParseMemberAccess(Type? type, Expression? expression) { if (expression != null) { @@ -1618,7 +1621,7 @@ Expression ParseMemberAccess(Type type, Expression expression) { if (expression != null && type != typeof(string)) { - Type enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type); + var enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type); if (enumerableType != null) { Type elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0]; @@ -1627,16 +1630,16 @@ Expression ParseMemberAccess(Type type, Expression expression) } Expression[] args = ParseArgumentList(); - switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out MethodBase mb)) + switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out var mb)) { case 0: throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type)); case 1: - MethodInfo method = (MethodInfo)mb; - if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) + MethodInfo method = (MethodInfo)mb!; + if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) { - throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType)); + throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType!)); } if (method.IsGenericMethod) @@ -1646,10 +1649,8 @@ Expression ParseMemberAccess(Type type, Expression expression) var constructedMethod = method.MakeGenericMethod(typeArguments.ToArray()); return Expression.Call(expression, constructedMethod, args); } - else - { - return Expression.Call(expression, method, args); - } + + return Expression.Call(expression, method, args); default: throw ParseError(errorPos, Res.AmbiguousMethodInvocation, id, TypeHelper.GetTypeName(type)); @@ -1668,7 +1669,7 @@ Expression ParseMemberAccess(Type type, Expression expression) return Expression.MakeIndex(expression, typeof(DynamicClass).GetProperty("Item"), new[] { Expression.Constant(id) }); } #endif - MemberInfo member = FindPropertyOrField(type, id, expression == null); + MemberInfo? member = FindPropertyOrField(type!, id, expression == null); if (member is PropertyInfo property) { return Expression.Property(expression, property); @@ -1681,7 +1682,7 @@ Expression ParseMemberAccess(Type type, Expression expression) if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && expression != null) { - MethodInfo indexerMethod = expression.Type.GetMethod("get_Item", new[] { typeof(string) }); + var indexerMethod = expression.Type.GetMethod("get_Item", new[] { typeof(string) }); if (indexerMethod != null) { return Expression.Call(expression, indexerMethod, Expression.Constant(id)); @@ -1696,7 +1697,7 @@ Expression ParseMemberAccess(Type type, Expression expression) } #endif // Parse as Lambda - if (_textParser.CurrentToken.Id == TokenId.Lambda && _it.Type == type) + if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == type) { return ParseAsLambda(id); } @@ -1713,8 +1714,8 @@ Expression ParseMemberAccess(Type type, Expression expression) private Expression ParseAsLambda(string id) { // This might be an internal variable for use within a lambda expression, so store it as such - _internals.Add(id, _it); - string _previousItName = ItName; + _internals.Add(id, _it!); + string previousItName = ItName; // Also store ItName (only once) if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT)) @@ -1730,7 +1731,7 @@ private Expression ParseAsLambda(string id) // Restore previous context and clear internals _internals.Remove(id); - ItName = _previousItName; + ItName = previousItName; return exp; } @@ -1761,7 +1762,7 @@ private Expression ParseAsEnum(string id) throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString); } - string enumValueAsString = parts.LastOrDefault(); + var enumValueAsString = parts.LastOrDefault(); if (enumValueAsString == null) { throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueExpected); @@ -1776,14 +1777,14 @@ private Expression ParseAsEnum(string id) return Expression.Constant(enumValue); } - Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type type) + private Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type) { bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null; bool isDictionary = TypeHelper.IsDictionary(type); var oldParent = _parent; - ParameterExpression outerIt = _it; + ParameterExpression? outerIt = _it; ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames); _parent = _it; @@ -1805,7 +1806,7 @@ Expression ParseEnumerable(Expression instance, Type elementType, string methodN if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, null, ref args)) { - var method = type.GetMethod(methodName); + var method = type!.GetMethod(methodName)!; return Expression.Call(instance, method, args); } @@ -1890,7 +1891,7 @@ private Type ResolveTypeFromArgumentExpression(string functionName, Expression a switch (constantExpression.Value) { case string typeName: - return ResolveTypeStringFromArgument(functionName, typeName); + return ResolveTypeStringFromArgument(typeName); case Type type: return type; @@ -1904,9 +1905,9 @@ private Type ResolveTypeFromArgumentExpression(string functionName, Expression a } } - private Type ResolveTypeStringFromArgument(string functionName, string typeName) + private Type ResolveTypeStringFromArgument(string typeName) { - Type resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); + var resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); if (resultType == null) { throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, typeName); @@ -1915,7 +1916,7 @@ private Type ResolveTypeStringFromArgument(string functionName, string typeName) return resultType; } - Expression[] ParseArgumentList() + private Expression[] ParseArgumentList() { _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); _textParser.NextToken(); @@ -1925,7 +1926,7 @@ Expression[] ParseArgumentList() return args; } - Expression[] ParseArguments() + private Expression[] ParseArguments() { var argList = new List(); while (true) @@ -1947,7 +1948,7 @@ Expression[] ParseArguments() return argList.ToArray(); } - Expression ParseElementAccess(Expression expr) + private Expression ParseElementAccess(Expression expr) { int errorPos = _textParser.CurrentToken.Pos; _textParser.ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected); @@ -1963,14 +1964,14 @@ Expression ParseElementAccess(Expression expr) { throw ParseError(errorPos, Res.CannotIndexMultiDimArray); } - Expression index = _parsingConfig.ExpressionPromoter.Promote(args[0], typeof(int), true, false); - if (index == null) + var indexExpression = _parsingConfig.ExpressionPromoter.Promote(args[0], typeof(int), true, false); + if (indexExpression == null) { throw ParseError(errorPos, Res.InvalidIndex); } - return Expression.ArrayIndex(expr, index); + return Expression.ArrayIndex(expr, indexExpression); } switch (_methodFinder.FindIndexer(expr.Type, args, out var mb)) @@ -1978,8 +1979,9 @@ Expression ParseElementAccess(Expression expr) case 0: throw ParseError(errorPos, Res.NoApplicableIndexer, TypeHelper.GetTypeName(expr.Type)); + case 1: - var indexMethod = (MethodInfo)mb; + var indexMethod = (MethodInfo)mb!; var indexParameterType = indexMethod.GetParameters().First().ParameterType; var indexArgumentExpression = args[0]; // Indexer only has 1 parameter, so we can use args[0] here @@ -2007,7 +2009,7 @@ internal static Type ToNullableType(Type type) return typeof(Nullable<>).MakeGenericType(type); } - static bool TryGetMemberName(Expression expression, out string memberName) + private static bool TryGetMemberName(Expression expression, out string? memberName) { var memberExpression = expression as MemberExpression; if (memberExpression == null && expression.NodeType == ExpressionType.Coalesce) @@ -2033,7 +2035,7 @@ static bool TryGetMemberName(Expression expression, out string memberName) return false; } - void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) + private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) { Expression[] args = { expr }; @@ -2045,7 +2047,7 @@ void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, expr = args[0]; } - static string GetOverloadedOperationName(TokenId tokenId) + private static string? GetOverloadedOperationName(TokenId tokenId) { switch (tokenId) { @@ -2059,7 +2061,7 @@ static string GetOverloadedOperationName(TokenId tokenId) } } - void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref Expression left, ref Expression right, int errorPos) + private void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref Expression left, ref Expression right, int errorPos) { Expression[] args = { left, right }; @@ -2086,26 +2088,24 @@ void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref E right = args[1]; } - static Exception IncompatibleOperandError(string opName, Expression expr, int errorPos) + private static Exception IncompatibleOperandError(string opName, Expression expr, int errorPos) { return ParseError(errorPos, Res.IncompatibleOperand, opName, TypeHelper.GetTypeName(expr.Type)); } - static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int errorPos) + private static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int errorPos) { return ParseError(errorPos, Res.IncompatibleOperands, opName, TypeHelper.GetTypeName(left.Type), TypeHelper.GetTypeName(right.Type)); } - private MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) + private MemberInfo? FindPropertyOrField(Type type, string memberName, bool staticAccess) { #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { - MemberInfo[] members = null; - var findMembersType = _parsingConfig?.IsCaseSensitive == true ? Type.FilterName : Type.FilterNameIgnoreCase; - members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, flags, findMembersType, memberName); + var members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, flags, findMembersType, memberName); if (members.Length != 0) { @@ -2118,7 +2118,7 @@ private MemberInfo FindPropertyOrField(Type type, string memberName, bool static foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { // Try to find a property with the specified memberName - MemberInfo member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); + MemberInfo? member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); if (member != null) { return member; @@ -2137,12 +2137,12 @@ private MemberInfo FindPropertyOrField(Type type, string memberName, bool static #endif } - bool TokenIdentifierIs(string id) + private bool TokenIdentifierIs(string id) { return _textParser.CurrentToken.Id == TokenId.Identifier && string.Equals(id, _textParser.CurrentToken.Text, StringComparison.OrdinalIgnoreCase); } - string GetIdentifier() + private string GetIdentifier() { _textParser.ValidateToken(TokenId.Identifier, Res.IdentifierExpected); string id = _textParser.CurrentToken.Text; @@ -2154,14 +2154,14 @@ string GetIdentifier() return id; } - Exception ParseError(string format, params object[] args) + private Exception ParseError(string format, params object[] args) { - return ParseError(_textParser?.CurrentToken.Pos ?? 0, format, args); + return ParseError(_textParser.CurrentToken.Pos, format, args); } - static Exception ParseError(int pos, string format, params object[] args) + private static Exception ParseError(int pos, string format, params object[] args) { return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs index f5632b16..fea5eb2f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs @@ -19,8 +19,8 @@ public ExpressionPromoter(ParsingConfig config) _numberParser = new NumberParser(config); } - /// - public virtual Expression Promote(Expression expr, Type type, bool exact, bool convertExpr) + /// + public virtual Expression? Promote(Expression expr, Type type, bool exact, bool convertExpr) { if (expr.Type == type || type.IsGenericParameter) { @@ -38,10 +38,10 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c } else { - if (ConstantExpressionHelper.TryGetText(ce, out string text)) + if (ConstantExpressionHelper.TryGetText(ce, out var text)) { Type target = TypeHelper.GetNonNullableType(type); - object value = null; + object? value = null; #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) switch (Type.GetTypeCode(ce.Type)) @@ -50,24 +50,24 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); // Make sure an enum value stays an enum value if (target.IsEnum) { - value = Enum.ToObject(target, value); + value = Enum.ToObject(target, value!); } break; case TypeCode.Double: if (target == typeof(decimal) || target == typeof(double)) { - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); } break; case TypeCode.String: - value = TypeHelper.ParseEnum(text, target); + value = TypeHelper.ParseEnum(text!, target); break; } #else @@ -80,19 +80,19 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c } else { - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); } } else if (ce.Type == typeof(double)) { if (target == typeof(decimal) || target == typeof(double)) { - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); } } else if (ce.Type == typeof(string)) { - value = TypeHelper.ParseEnum(text, target); + value = TypeHelper.ParseEnum(text!, target); } #endif if (value != null) @@ -121,4 +121,4 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c return null; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs index cabae88c..8fb14e71 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs @@ -26,7 +26,7 @@ internal interface IExpressionHelper void OptimizeForEqualityIfPossible(ref Expression left, ref Expression right); - Expression OptimizeStringForEqualityIfPossible(string text, Type type); + Expression? OptimizeStringForEqualityIfPossible(string text, Type type); bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, bool addSelf, out Expression generatedExpression); diff --git a/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs b/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs index 6ec7dd886..29d8ba7f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs @@ -13,10 +13,10 @@ public interface IExpressionPromoter /// Promote an expression /// /// Source expression - /// Destionation data type to promote + /// Destination data type to promote /// If the match must be exact /// Convert expression - /// The promoted - Expression Promote(Expression expr, Type type, bool exact, bool convertExpr); + /// The promoted or null. + Expression? Promote(Expression expr, Type type, bool exact, bool convertExpr); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs b/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs index 0de66306..ece62c52 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs @@ -1,10 +1,9 @@ using System.Linq.Expressions; -using JetBrains.Annotations; namespace System.Linq.Dynamic.Core.Parser { interface ITypeFinder { - Type FindTypeByName([NotNull] string name, [CanBeNull] ParameterExpression[] expressions, bool forceUseCustomTypeProvider); + Type? FindTypeByName(string name, ParameterExpression?[]? expressions, bool forceUseCustomTypeProvider); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs index fe15bcc2..791e506c 100644 --- a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Globalization; +using System.Globalization; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; @@ -12,11 +11,11 @@ namespace System.Linq.Dynamic.Core.Parser /// public class NumberParser { - private static readonly Regex RegexBinary32 = new Regex("^[01]{1,32}$", RegexOptions.Compiled); - private static readonly Regex RegexBinary64 = new Regex("^[01]{1,64}$", RegexOptions.Compiled); - private static readonly char[] Qualifiers = new[] { 'U', 'u', 'L', 'l', 'F', 'f', 'D', 'd', 'M', 'm' }; - private static readonly char[] QualifiersHex = new[] { 'U', 'u', 'L', 'l' }; - private static readonly string[] QualifiersReal = new[] { "F", "f", "D", "d", "M", "m" }; + private static readonly Regex RegexBinary32 = new("^[01]{1,32}$", RegexOptions.Compiled); + private static readonly Regex RegexBinary64 = new("^[01]{1,64}$", RegexOptions.Compiled); + private static readonly char[] Qualifiers = { 'U', 'u', 'L', 'l', 'F', 'f', 'D', 'd', 'M', 'm' }; + private static readonly char[] QualifiersHex = { 'U', 'u', 'L', 'l' }; + private static readonly string[] QualifiersReal = { "F", "f", "D", "d", "M", "m" }; private readonly CultureInfo _culture; @@ -24,7 +23,7 @@ public class NumberParser /// Initializes a new instance of the class. /// /// The ParsingConfig. - public NumberParser([CanBeNull] ParsingConfig config) + public NumberParser(ParsingConfig? config) { _culture = config?.NumberParseCulture ?? CultureInfo.InvariantCulture; } @@ -44,7 +43,7 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) var isBinary = text.StartsWith(isNegative ? "-0b" : "0b", StringComparison.OrdinalIgnoreCase); var qualifiers = isHexadecimal ? QualifiersHex : Qualifiers; - string qualifier = null; + string? qualifier = null; if (qualifiers.Contains(last)) { int pos = text.Length - 1, count = 0; @@ -74,7 +73,7 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) throw new ParseException(string.Format(_culture, Res.InvalidIntegerLiteral, text), tokenPosition); } - if (!string.IsNullOrEmpty(qualifier)) + if (!string.IsNullOrEmpty(qualifier) && qualifier!.Length > 0) { if (qualifier == "U" || qualifier == "u") { @@ -132,7 +131,7 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) value = -value; } - if (!string.IsNullOrEmpty(qualifier)) + if (!string.IsNullOrEmpty(qualifier) && qualifier!.Length > 0) { if (qualifier == "L" || qualifier == "l") { @@ -164,18 +163,18 @@ public Expression ParseRealLiteral(string text, char qualifier, bool stripQualif { case 'f': case 'F': - return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(float)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(float))!, text); case 'm': case 'M': - return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(decimal)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(decimal))!, text); case 'd': case 'D': - return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(double)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(double))!, text); default: - return ConstantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(double)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(double))!, text); } } @@ -185,10 +184,10 @@ public Expression ParseRealLiteral(string text, char qualifier, bool stripQualif /// The text. /// The type. /// The result. - public bool TryParseNumber(string text, Type type, out object result) + public bool TryParseNumber(string text, Type type, out object? result) { result = ParseNumber(text, type); - return type != null; + return result != null; } /// @@ -196,7 +195,7 @@ public bool TryParseNumber(string text, Type type, out object result) /// /// The text. /// The type. - public object ParseNumber(string text, Type type) + public object? ParseNumber(string text, Type type) { try { @@ -297,4 +296,4 @@ private Expression ParseAsBinary(int tokenPosition, string text, bool isNegative throw new ParseException(string.Format(_culture, Res.InvalidBinaryIntegerLiteral, text), tokenPosition); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs index 4bf115ba..d42377a8 100644 --- a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs @@ -74,7 +74,7 @@ private static void TryAdd(string typeName, int x) { try { - Type efType = Type.GetType(typeName); + Type? efType = Type.GetType(typeName); if (efType != null) { PredefinedTypes.Add(efType, x); diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs index cdfcf7a7..40b41848 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs @@ -17,7 +17,7 @@ public MethodFinder(ParsingConfig parsingConfig) _parsingConfig = parsingConfig; } - public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expression instance, ref Expression[] args) + public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expression? instance, ref Expression[] args) { // NOTE: `instance` is not passed by ref in the method signature by design. The ContainsMethod should not change the instance. // However, args by reference is required for backward compatibility (removing "ref" will break some tests) @@ -25,7 +25,7 @@ public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expr return FindMethod(type, methodName, staticAccess, ref instance, ref args, out _) == 1; } - public int FindMethod(Type type, string methodName, bool staticAccess, ref Expression instance, ref Expression[] args, out MethodBase method) + public int FindMethod(Type? type, string methodName, bool staticAccess, ref Expression? instance, ref Expression[] args, out MethodBase? method) { #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); @@ -68,6 +68,8 @@ public int FindMethod(Type type, string methodName, bool staticAccess, ref Expre argsList.Insert(0, instance); var extensionMethodArgs = argsList.ToArray(); + + // ReSharper disable once RedundantEnumerableCastCall int count = FindBestMethodBasedOnArguments(methods.Cast(), ref extensionMethodArgs, out method); if (count != 0) { @@ -82,7 +84,7 @@ public int FindMethod(Type type, string methodName, bool staticAccess, ref Expre return 0; } - public int FindBestMethodBasedOnArguments(IEnumerable methods, ref Expression[] args, out MethodBase method) + public int FindBestMethodBasedOnArguments(IEnumerable methods, ref Expression[] args, out MethodBase? method) { // Passing args by reference is now required with the params array support. var inlineArgs = args; @@ -124,7 +126,7 @@ public int FindBestMethodBasedOnArguments(IEnumerable methods, ref E return applicable.Length; } - public int FindIndexer(Type type, Expression[] args, out MethodBase method) + public int FindIndexer(Type type, Expression[] args, out MethodBase? method) { foreach (Type t in SelfAndBaseTypes(type)) { @@ -179,19 +181,19 @@ bool IsApplicable(MethodData method, Expression[] args) else { var paramType = method.Parameters.Last().ParameterType; - var paramElementType = paramType.GetElementType(); + var paramElementType = paramType.GetElementType()!; var arrayInitializerExpressions = new List(); for (int j = method.Parameters.Length - 1; j < args.Length; j++) { - Expression promoted = _parsingConfig.ExpressionPromoter.Promote(args[j], paramElementType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); - if (promoted == null) + var promotedExpression = _parsingConfig.ExpressionPromoter.Promote(args[j], paramElementType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); + if (promotedExpression == null) { return false; } - arrayInitializerExpressions.Add(promoted); + arrayInitializerExpressions.Add(promotedExpression); } var paramExpression = Expression.NewArrayInit(paramElementType, arrayInitializerExpressions); @@ -207,12 +209,12 @@ bool IsApplicable(MethodData method, Expression[] args) return false; } - Expression promoted = _parsingConfig.ExpressionPromoter.Promote(args[i], pi.ParameterType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); - if (promoted == null) + var promotedExpression = _parsingConfig.ExpressionPromoter.Promote(args[i], pi.ParameterType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); + if (promotedExpression == null) { return false; } - promotedArgs[i] = promoted; + promotedArgs[i] = promotedExpression; } } @@ -297,9 +299,9 @@ CompareConversionType CompareConversions(Type source, Type first, Type second) return CompareConversionType.Both; } - IEnumerable SelfAndBaseTypes(Type type) + IEnumerable SelfAndBaseTypes(Type? type) { - if (type.GetTypeInfo().IsInterface) + if (type?.GetTypeInfo().IsInterface == true) { var types = new List(); AddInterface(types, type); @@ -308,7 +310,7 @@ IEnumerable SelfAndBaseTypes(Type type) return SelfAndBaseClasses(type); } - IEnumerable SelfAndBaseClasses(Type type) + IEnumerable SelfAndBaseClasses(Type? type) { while (type != null) { diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs b/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs index 08e27cd6..c3175069 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Linq.Dynamic.Core.Validation; +using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; namespace System.Linq.Dynamic.Core.Parser @@ -9,39 +8,39 @@ internal class TypeFinder : ITypeFinder private readonly IKeywordsHelper _keywordsHelper; private readonly ParsingConfig _parsingConfig; - public TypeFinder([NotNull] ParsingConfig parsingConfig, [NotNull] IKeywordsHelper keywordsHelper) + public TypeFinder(ParsingConfig parsingConfig, IKeywordsHelper keywordsHelper) { - Check.NotNull(parsingConfig, nameof(parsingConfig)); - Check.NotNull(keywordsHelper, nameof(keywordsHelper)); + Check.NotNull(parsingConfig); + Check.NotNull(keywordsHelper); _keywordsHelper = keywordsHelper; _parsingConfig = parsingConfig; } - public Type FindTypeByName(string name, ParameterExpression[] expressions, bool forceUseCustomTypeProvider) + public Type? FindTypeByName(string name, ParameterExpression?[]? expressions, bool forceUseCustomTypeProvider) { - Check.NotEmpty(name, nameof(name)); + Check.NotEmpty(name); - _keywordsHelper.TryGetValue(name, out object type); + _keywordsHelper.TryGetValue(name, out var type); - if (type is Type result) + if (type is Type sameType) { - return result; + return sameType; } - if (expressions != null && TryResolveTypeUsingExpressions(name, expressions, out result)) + if (expressions != null && TryResolveTypeUsingExpressions(name, expressions, out var resolvedType)) { - return result; + return resolvedType; } return ResolveTypeByUsingCustomTypeProvider(name, forceUseCustomTypeProvider); } - private Type ResolveTypeByUsingCustomTypeProvider(string name, bool forceUseCustomTypeProvider) + private Type? ResolveTypeByUsingCustomTypeProvider(string name, bool forceUseCustomTypeProvider) { if ((forceUseCustomTypeProvider || _parsingConfig.AllowNewToEvaluateAnyType) && _parsingConfig.CustomTypeProvider != null) { - Type resolvedType = _parsingConfig.CustomTypeProvider.ResolveType(name); + var resolvedType = _parsingConfig.CustomTypeProvider.ResolveType(name); if (resolvedType != null) { return resolvedType; @@ -57,11 +56,11 @@ private Type ResolveTypeByUsingCustomTypeProvider(string name, bool forceUseCust return null; } - private bool TryResolveTypeUsingExpressions(string name, ParameterExpression[] expressions, out Type result) + private bool TryResolveTypeUsingExpressions(string name, ParameterExpression?[] expressions, out Type? result) { foreach (var expression in expressions.Where(e => e != null)) { - if (name == expression.Type.Name) + if (name == expression!.Type.Name) { result = expression.Type; return true; @@ -89,4 +88,4 @@ private bool TryResolveTypeUsingExpressions(string name, ParameterExpression[] e return false; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index 22e50778..30a591cf 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -6,7 +6,7 @@ namespace System.Linq.Dynamic.Core.Parser { internal static class TypeHelper { - public static Type FindGenericType(Type generic, Type type) + public static Type? FindGenericType(Type generic, Type? type) { while (type != null && type != typeof(object)) { @@ -19,10 +19,10 @@ public static Type FindGenericType(Type generic, Type type) { foreach (Type interfaceType in type.GetInterfaces()) { - Type found = FindGenericType(generic, interfaceType); - if (found != null) + var foundType = FindGenericType(generic, interfaceType); + if (foundType != null) { - return found; + return foundType; } } } @@ -377,8 +377,13 @@ private static int GetNumericTypeKind(Type type) #endif } - public static string GetTypeName(Type type) + public static string GetTypeName(Type? type) { + if (type == null) + { + return "null"; + } + Type baseType = GetNonNullableType(type); string name = baseType.Name; @@ -404,7 +409,7 @@ public static Type GetUnderlyingType(Type type) Type[] genericTypeArguments = type.GetGenericArguments(); if (genericTypeArguments.Any()) { - var outerType = GetUnderlyingType(genericTypeArguments.LastOrDefault()); + var outerType = GetUnderlyingType(genericTypeArguments.LastOrDefault()!); return Nullable.GetUnderlyingType(type) == outerType ? type : outerType; } @@ -443,9 +448,9 @@ private static void AddInterface(List types, Type type) } } - public static object ParseEnum(string value, Type type) + public static object? ParseEnum(string value, Type? type) { - if (type.GetTypeInfo().IsEnum && Enum.IsDefined(type, value)) + if (type is { } && type.GetTypeInfo().IsEnum && Enum.IsDefined(type, value)) { return Enum.Parse(type, value, true); } @@ -453,15 +458,16 @@ public static object ParseEnum(string value, Type type) return null; } - public static bool IsDictionary(Type type) + public static bool IsDictionary(Type? type) { return FindGenericType(typeof(IDictionary<,>), type) != null || #if NET35 || NET40 + // ReSharper disable once RedundantLogicalConditionalExpressionOperand false; #else FindGenericType(typeof(IReadOnlyDictionary<,>), type) != null; #endif } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index 856c67b4..da6c2a03 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -35,11 +35,11 @@ public class ParsingConfig RenameEmptyParameterExpressionNames = true }; - private IDynamicLinkCustomTypeProvider _customTypeProvider; + private IDynamicLinkCustomTypeProvider? _customTypeProvider; - private IExpressionPromoter _expressionPromoter; + private IExpressionPromoter? _expressionPromoter; - private IQueryableAnalyzer _queryableAnalyzer; + private IQueryableAnalyzer? _queryableAnalyzer; /// /// Gets or sets the . @@ -50,7 +50,7 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider { #if !( WINDOWS_APP || UAP10_0 || NETSTANDARD) // only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework and NET Core App 2.x - return _customTypeProvider ?? (_customTypeProvider = new DefaultDynamicLinqCustomTypeProvider()); + return _customTypeProvider ??= new DefaultDynamicLinqCustomTypeProvider(); #else return _customTypeProvider; #endif @@ -58,6 +58,7 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider set { + // ReSharper disable once RedundantCheckBeforeAssignment if (_customTypeProvider != value) { _customTypeProvider = value; @@ -70,10 +71,11 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider /// public IExpressionPromoter ExpressionPromoter { - get => _expressionPromoter ?? (_expressionPromoter = new ExpressionPromoter(this)); + get => _expressionPromoter ??= new ExpressionPromoter(this); set { + // ReSharper disable once RedundantCheckBeforeAssignment if (_expressionPromoter != value) { _expressionPromoter = value; @@ -88,11 +90,12 @@ public IQueryableAnalyzer QueryableAnalyzer { get { - return _queryableAnalyzer ?? (_queryableAnalyzer = new DefaultQueryableAnalyzer()); + return _queryableAnalyzer ??= new DefaultQueryableAnalyzer(); } set { + // ReSharper disable once RedundantCheckBeforeAssignment if (_queryableAnalyzer != value) { _queryableAnalyzer = value; @@ -116,7 +119,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool EvaluateGroupByAtDatabase { get; set; } = false; + public bool EvaluateGroupByAtDatabase { get; set; } /// /// Use Parameterized Names in generated dynamic SQL query. @@ -145,7 +148,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool RenameEmptyParameterExpressionNames { get; set; } = false; + public bool RenameEmptyParameterExpressionNames { get; set; } /// /// By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use @@ -185,12 +188,12 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is CultureInfo.InvariantCulture /// - public CultureInfo NumberParseCulture { get; set; } = CultureInfo.InvariantCulture; + public CultureInfo? NumberParseCulture { get; set; } = CultureInfo.InvariantCulture; /// /// Additional TypeConverters /// - public IDictionary TypeConverters { get; set; } + public IDictionary? TypeConverters { get; set; } /// /// When using the NullPropagating function np(...), use a "default value" for non-nullable value types instead of "null value". diff --git a/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs b/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs index fa42300f..83839d82 100644 --- a/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs +++ b/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs @@ -13,7 +13,7 @@ public class TextParser private static readonly char[] EscapeCharacters = { '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v' }; // These aliases are supposed to simply the where clause and make it more human readable - private static readonly Dictionary PredefinedOperatorAliases = new Dictionary(StringComparer.OrdinalIgnoreCase) + private static readonly Dictionary PredefinedOperatorAliases = new(StringComparer.OrdinalIgnoreCase) { { "eq", TokenId.Equal }, { "equal", TokenId.Equal }, @@ -36,7 +36,6 @@ public class TextParser { "mod", TokenId.Percent } }; - private readonly ParsingConfig _config; private readonly char _numberDecimalSeparator; private readonly string _text; private readonly int _textLen; @@ -56,7 +55,6 @@ public class TextParser /// public TextParser(ParsingConfig config, string text) { - _config = config; _numberDecimalSeparator = config.NumberParseCulture?.NumberFormat.NumberDecimalSeparator[0] ?? DefaultNumberDecimalSeparator; _text = text; @@ -100,6 +98,7 @@ public void NextToken() NextChar(); } + // ReSharper disable once RedundantAssignment TokenId tokenId = TokenId.Unknown; int tokenPos = _textPos; @@ -449,7 +448,7 @@ public void NextToken() /// /// The tokenId to check. /// The (optional) error message. - public void ValidateToken(TokenId tokenId, string errorMessage = null) + public void ValidateToken(TokenId tokenId, string? errorMessage = null) { if (CurrentToken.Id != tokenId) { @@ -514,7 +513,7 @@ private static bool IsHexChar(char c) if (c <= '\x007f') { c |= (char)0x20; - return c >= 'a' && c <= 'f'; + return c is >= 'a' and <= 'f'; } return false; @@ -522,7 +521,7 @@ private static bool IsHexChar(char c) private static bool IsZeroOrOne(char c) { - return c == '0' || c == '1'; + return c is '0' or '1'; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs b/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs index 3bb0e06a..a0b4e954 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs @@ -1,23 +1,22 @@ using System.ComponentModel; using System.Globalization; -namespace System.Linq.Dynamic.Core.TypeConverters +namespace System.Linq.Dynamic.Core.TypeConverters; + +internal class CustomDateTimeConverter : DateTimeOffsetConverter { - internal class CustomDateTimeConverter : DateTimeOffsetConverter + /// + /// Converts the specified object to a . + /// + /// The date format context. + /// The date culture. + /// The object to be converted. + /// A that represents the specified object. + /// The conversion cannot be performed. + public override object? ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - /// - /// Converts the specified object to a . - /// - /// The date format context. - /// The date culture. - /// The object to be converted. - /// A that represents the specified object. - /// The conversion cannot be performed. - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - var dateTimeOffset = base.ConvertFrom(context, culture, value) as DateTimeOffset?; + var dateTimeOffset = base.ConvertFrom(context, culture, value) as DateTimeOffset?; - return dateTimeOffset?.UtcDateTime; - } + return dateTimeOffset?.UtcDateTime; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs index afbcb033..ad947160 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs @@ -1,15 +1,13 @@ -using JetBrains.Annotations; -using System.ComponentModel; +using System.ComponentModel; -namespace System.Linq.Dynamic.Core.TypeConverters +namespace System.Linq.Dynamic.Core.TypeConverters; + +interface ITypeConverterFactory { - interface ITypeConverterFactory - { - /// - /// Returns a type converter for the specified type. - /// - /// The System.Type of the target component. - /// A System.ComponentModel.TypeConverter for the specified type. - TypeConverter GetConverter([NotNull] Type type); - } -} + /// + /// Returns a type converter for the specified type. + /// + /// The System.Type of the target component. + /// A System.ComponentModel.TypeConverter for the specified type. + TypeConverter GetConverter(Type type); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs index 4fdadd0a..d6a4bc92 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.ComponentModel; +using System.ComponentModel; using System.Linq.Dynamic.Core.Parser; using System.Linq.Dynamic.Core.Validation; @@ -9,17 +8,15 @@ internal class TypeConverterFactory : ITypeConverterFactory { private readonly ParsingConfig _config; - public TypeConverterFactory([NotNull] ParsingConfig config) + public TypeConverterFactory(ParsingConfig config) { - Check.NotNull(config, nameof(config)); - - _config = config; + _config = Check.NotNull(config); } /// public TypeConverter GetConverter(Type type) { - Check.NotNull(type, nameof(type)); + Check.NotNull(type); if (_config.DateTimeIsParsedAsUTC && (type == typeof(DateTime) || type == typeof(DateTime?))) { @@ -50,4 +47,4 @@ public TypeConverter GetConverter(Type type) #endif } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs b/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs index 960baa12..31b0c558 100644 --- a/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs +++ b/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs @@ -1,74 +1,70 @@ -using JetBrains.Annotations; -using System.Linq.Dynamic.Core.Validation; +using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core.Util +namespace System.Linq.Dynamic.Core.Util; + +/// +/// Renames a single (Typed)ParameterExpression in an Expression. +/// +/// +internal class ParameterExpressionRenamer : ExpressionVisitor { + private readonly string _newName; + private readonly string _oldName; + + private ParameterExpression? _parameterExpression; + /// - /// Renames a single (Typed)ParameterExpression in an Expression. + /// Initializes a new instance of the class. /// - /// - internal class ParameterExpressionRenamer : ExpressionVisitor + /// The new name (the oldName is assumed to be ""). + public ParameterExpressionRenamer(string newName) : this(string.Empty, newName) { - private readonly string _newName; - private readonly string _oldName; - - private ParameterExpression _parameterExpression; - - /// - /// Initializes a new instance of the class. - /// - /// The new name (the oldName is assumed to be ""). - public ParameterExpressionRenamer([NotNull] string newName) : this("", newName) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The old name. - /// The new name. - public ParameterExpressionRenamer([NotNull] string oldName, [NotNull] string newName) - { - Check.NotNull(oldName, nameof(oldName)); - Check.NotEmpty(newName, nameof(newName)); + /// + /// Initializes a new instance of the class. + /// + /// The old name. + /// The new name. + public ParameterExpressionRenamer(string oldName, string newName) + { + Check.NotNull(oldName); + Check.NotEmpty(newName); - _oldName = oldName; - _newName = newName; - } + _oldName = oldName; + _newName = newName; + } - /// - /// Renames a single (Typed)ParameterExpression from specified expression. - /// - /// The expression. - /// The new generated (Typed)ParameterExpression. - /// Renamed Expression - public Expression Rename(Expression expression, out ParameterExpression parameterExpression) - { - var visitedExpression = Visit(expression); + /// + /// Renames a single (Typed)ParameterExpression from specified expression. + /// + /// The expression. + /// The new generated (Typed)ParameterExpression. + /// Renamed Expression + public Expression Rename(Expression expression, out ParameterExpression? parameterExpression) + { + var visitedExpression = Visit(expression); - parameterExpression = _parameterExpression; + parameterExpression = _parameterExpression; - return visitedExpression; - } + return visitedExpression; + } - /// - protected override Expression VisitParameter(ParameterExpression node) + /// + protected override Expression VisitParameter(ParameterExpression node) + { + if (string.Equals(_oldName, node.Name, StringComparison.Ordinal)) { - if (string.Equals(_oldName, node.Name, StringComparison.Ordinal)) - { - if (_parameterExpression == null) - { - _parameterExpression = ParameterExpressionHelper.CreateParameterExpression(node.Type, _newName); - } - - return _parameterExpression; - // throw new InvalidOperationException($"The {nameof(ParameterExpressionRenamer)} can only rename 1 (Typed)ParameterExpression in an Expression."); - } - else + if (_parameterExpression == null) { - return node; + _parameterExpression = ParameterExpressionHelper.CreateParameterExpression(node.Type, _newName); } + + return _parameterExpression; + // throw new InvalidOperationException($"The {nameof(ParameterExpressionRenamer)} can only rename 1 (Typed)ParameterExpression in an Expression."); } + + return node; } } diff --git a/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs b/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs index 69b93247..d304f5a5 100644 --- a/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs @@ -1,47 +1,46 @@ using System.Linq.Expressions; using System.Reflection; -namespace System.Linq.Dynamic.Core.Util +namespace System.Linq.Dynamic.Core.Util; + +internal static class QueryableMethodFinder { - internal static class QueryableMethodFinder + public static MethodInfo GetGenericMethod(string name) { - public static MethodInfo GetGenericMethod(string name) - { - return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => mi.IsGenericMethod); - } + return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => mi.IsGenericMethod); + } - public static MethodInfo GetMethod(string name, Type argumentType, Type returnType, int parameterCount = 0, Func predicate = null) => - GetMethod(name, returnType, parameterCount, mi => mi.ToString().Contains(argumentType.ToString()) && ((predicate == null) || predicate(mi))); + public static MethodInfo GetMethod(string name, Type argumentType, Type returnType, int parameterCount = 0, Func? predicate = null) => + GetMethod(name, returnType, parameterCount, mi => mi.ToString().Contains(argumentType.ToString()) && ((predicate == null) || predicate(mi))); - public static MethodInfo GetMethod(string name, Type returnType, int parameterCount = 0, Func predicate = null) => - GetMethod(name, parameterCount, mi => (mi.ReturnType == returnType) && ((predicate == null) || predicate(mi))); + public static MethodInfo GetMethod(string name, Type returnType, int parameterCount = 0, Func? predicate = null) => + GetMethod(name, parameterCount, mi => (mi.ReturnType == returnType) && ((predicate == null) || predicate(mi))); - public static MethodInfo GetMethodWithExpressionParameter(string name) => - GetMethod(name, 1, mi => - mi.GetParameters().Length == 2 && - mi.GetParameters()[1].ParameterType.GetTypeInfo().IsGenericType && - mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>) && - mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetTypeInfo().IsGenericType && - mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func<,>) - ); + public static MethodInfo GetMethodWithExpressionParameter(string name) => + GetMethod(name, 1, mi => + mi.GetParameters().Length == 2 && + mi.GetParameters()[1].ParameterType.GetTypeInfo().IsGenericType && + mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>) && + mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetTypeInfo().IsGenericType && + mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func<,>) + ); - public static MethodInfo GetMethodWithIntParameter(string name) => - GetMethod(name, 1, mi => - mi.GetParameters().Length == 2 && - mi.GetParameters()[1].ParameterType == typeof(int) - ); + public static MethodInfo GetMethodWithIntParameter(string name) => + GetMethod(name, 1, mi => + mi.GetParameters().Length == 2 && + mi.GetParameters()[1].ParameterType == typeof(int) + ); - public static MethodInfo GetMethod(string name, int parameterCount = 0, Func predicate = null) + public static MethodInfo GetMethod(string name, int parameterCount = 0, Func? predicate = null) + { + try + { + return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => + mi.GetParameters().Length == parameterCount + 1 && (predicate == null || predicate(mi))); + } + catch (Exception ex) { - try - { - return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => - mi.GetParameters().Length == parameterCount + 1 && (predicate == null || predicate(mi))); - } - catch (Exception ex) - { - throw new Exception("Specific method not found: " + name, ex); - } + throw new Exception("Specific method not found: " + name, ex); } } } diff --git a/src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs b/src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs new file mode 100644 index 00000000..96fa84d3 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs @@ -0,0 +1,15 @@ +#if !NETCOREAPP3_0_OR_GREATER +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute(string parameterName) + { + ParameterName = parameterName; + } + + public string ParameterName { get; } + } +} +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Validation/Check.cs b/src/System.Linq.Dynamic.Core/Validation/Check.cs index b58e16e8..a1c36983 100644 --- a/src/System.Linq.Dynamic.Core/Validation/Check.cs +++ b/src/System.Linq.Dynamic.Core/Validation/Check.cs @@ -1,136 +1,123 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; -using JetBrains.Annotations; -// using System.Reflection; +using System.Runtime.CompilerServices; + +// Copied from https://github.com/StefH/Stef.Validation +namespace System.Linq.Dynamic.Core.Validation; -// Copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Shared/Check.cs -namespace System.Linq.Dynamic.Core.Validation +[DebuggerStepThrough] +internal static class Check { - [DebuggerStepThrough] - internal static class Check + public static T Condition(T value, Predicate predicate, [CallerArgumentExpression("value")] string? parameterName = null) { - public static T Condition([ValidatedNotNull, NoEnumeration] T value, [ValidatedNotNull, NotNull] Predicate condition, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) + NotNull(predicate, nameof(predicate)); + + if (!predicate(value)) { - NotNull(condition, nameof(condition)); + NotNullOrEmpty(parameterName, nameof(parameterName)); + + throw new ArgumentOutOfRangeException(parameterName); + } - if (!condition(value)) - { - NotEmpty(parameterName, nameof(parameterName)); + return value; + } - throw new ArgumentOutOfRangeException(parameterName); - } + public static T NotNull(T value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - return value; + throw new ArgumentNullException(parameterName); } - [ContractAnnotation("value:null => halt")] - public static T NotNull([ValidatedNotNull, NoEnumeration] T value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - { - if (ReferenceEquals(value, null)) - { - NotEmpty(parameterName, nameof(parameterName)); + return value; + } - throw new ArgumentNullException(parameterName); - } + public static T NotNull(T value, string parameterName, string propertyName) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); + NotNullOrEmpty(propertyName, nameof(propertyName)); - return value; + throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName)); } - [ContractAnnotation("value:null => halt")] - public static T NotNull( - [NoEnumeration] T value, - [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName, - [ValidatedNotNull, NotNull] string propertyName) - { - if (ReferenceEquals(value, null)) - { - NotEmpty(parameterName, nameof(parameterName)); - NotEmpty(propertyName, nameof(propertyName)); + return value; + } - throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName)); - } + public static IEnumerable NotNullOrEmpty(IEnumerable value, [CallerArgumentExpression("value")] string? parameterName = null) + { + IEnumerable result = NotNull(value, parameterName); - return value; + // ReSharper disable once PossibleMultipleEnumeration + if (!result.Any()) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); + + throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName)); } - //[ContractAnnotation("value:null => halt")] - //public static IList NotEmpty(IList value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - //{ - // NotNull(value, parameterName); + // ReSharper disable once PossibleMultipleEnumeration + return result; + } - // if (value.Count == 0) - // { - // NotEmpty(parameterName, nameof(parameterName)); + public static string NotEmpty(string? value, [CallerArgumentExpression("value")] string? parameterName = null) => + NotNullOrWhiteSpace(value, parameterName); - // throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName)); - // } + public static string NotNullOrEmpty(string? value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - // return value; - //} + throw new ArgumentNullException(parameterName); + } - [ContractAnnotation("value:null => halt")] - public static string NotEmpty(string value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) + if (string.IsNullOrEmpty(value)) { - Exception e = null; - if (ReferenceEquals(value, null)) - { - e = new ArgumentNullException(parameterName); - } - else if (value.Trim().Length == 0) - { - e = new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); - } - - if (e != null) - { - NotEmpty(parameterName, nameof(parameterName)); - - throw e; - } - - return value; + throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); } - //public static string NullButNotEmpty(string value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - //{ - // if (!ReferenceEquals(value, null) && value.Length == 0) - // { - // NotEmpty(parameterName, nameof(parameterName)); + return value; + } - // throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); - // } + public static string NotNullOrWhiteSpace(string? value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - // return value; - //} + throw new ArgumentNullException(parameterName); + } - public static IList HasNoNulls(IList value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - where T : class + if (value.IsNullOrWhiteSpace()) { - NotNull(value, parameterName); + throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); + } - if (value.Any(e => e == null)) - { - NotEmpty(parameterName, nameof(parameterName)); + return value; + } - throw new ArgumentException(parameterName); - } + public static IEnumerable HasNoNulls(IEnumerable value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - return value; + throw new ArgumentNullException(parameterName); } - //public static Type ValidEntityType(Type value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - //{ - // if (!value.GetTypeInfo().IsClass) - // { - // NotEmpty(parameterName, nameof(parameterName)); + // ReSharper disable once PossibleMultipleEnumeration + if (value.Any(v => v is null)) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - // throw new ArgumentException(CoreStrings.InvalidEntityType(value, parameterName)); - // } + throw new ArgumentException(parameterName); + } - // return value; - //} + // ReSharper disable once PossibleMultipleEnumeration + return value; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs b/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs index d5570cad..c5f68b1b 100644 --- a/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs +++ b/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs @@ -1,41 +1,20 @@ -using System.Globalization; -using JetBrains.Annotations; +// Copied from https://github.com/StefH/Stef.Validation +namespace System.Linq.Dynamic.Core.Validation; -// copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Properties/CoreStrings.resx -namespace System.Linq.Dynamic.Core.Validation +internal static class CoreStrings { - internal static class CoreStrings + public static string ArgumentPropertyNull(string property, string argument) { - /// - /// The property '{property}' of the argument '{argument}' cannot be null. - /// - public static string ArgumentPropertyNull([CanBeNull] string property, [CanBeNull] string argument) - { - return string.Format(CultureInfo.CurrentCulture, "The property '{0}' of the argument '{1}' cannot be null.", property, argument); - } - - /// - /// The string argument '{argumentName}' cannot be empty. - /// - public static string ArgumentIsEmpty([CanBeNull] string argumentName) - { - return string.Format(CultureInfo.CurrentCulture, "The string argument '{0}' cannot be empty.", argumentName); - } + return $"The property '{property}' of the argument '{argument}' cannot be null."; + } - /// - /// The entity type '{type}' provided for the argument '{argumentName}' must be a reference type. - /// - public static string InvalidEntityType([CanBeNull] Type type, [CanBeNull] string argumentName) - { - return string.Format(CultureInfo.CurrentCulture, "The entity type '{0}' provided for the argument '{1}' must be a reference type.", type, argumentName); - } + public static string ArgumentIsEmpty(string? argumentName) + { + return $"Value cannot be empty. (Parameter '{argumentName}')"; + } - /// - /// The collection argument '{argumentName}' must contain at least one element. - /// - public static string CollectionArgumentIsEmpty([CanBeNull] string argumentName) - { - return string.Format(CultureInfo.CurrentCulture, "The collection argument '{0}' must contain at least one element.", argumentName); - } + public static string CollectionArgumentIsEmpty(string? argumentName) + { + return $"The collection argument '{argumentName}' must contain at least one element."; } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs index afc6b89e..4f90a753 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs @@ -135,7 +135,7 @@ public void ParameterExpressionHelper_CreateParameterExpression(Type type, strin public void ParameterExpressionHelper_IsNullOrWhiteSpace(string input, bool expectedResult) { // Arrange and Act - bool result = ParameterExpressionHelper.IsNullOrWhiteSpace(input); + bool result = input.IsNullOrWhiteSpace(); // Assert Check.That(result).IsEqualTo(expectedResult); From c1a977158e04d9c77ad07e21fb4646d9ea0aecec Mon Sep 17 00:00:00 2001 From: BBreiden Date: Sun, 23 Oct 2022 10:52:15 +0200 Subject: [PATCH 005/214] Init field only on first execution (#631) * Init field only on first execution * Test demonstrating issue #629 Co-authored-by: Boris Breidenbach --- src/System.Linq.Dynamic.Core/DynamicClass.cs | 22 ++++++++------- .../DynamicClassTest.cs | 27 +++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs diff --git a/src/System.Linq.Dynamic.Core/DynamicClass.cs b/src/System.Linq.Dynamic.Core/DynamicClass.cs index e8651bd8..4498e4e8 100644 --- a/src/System.Linq.Dynamic.Core/DynamicClass.cs +++ b/src/System.Linq.Dynamic.Core/DynamicClass.cs @@ -18,24 +18,28 @@ namespace System.Linq.Dynamic.Core; /// public abstract class DynamicClass : DynamicObject { - private readonly Dictionary _propertiesDictionary = new(); + private Dictionary? _propertiesDictionary = null; private Dictionary Properties { get { - foreach (PropertyInfo pi in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) + if (_propertiesDictionary == null) { - int parameters = pi.GetIndexParameters().Length; - if (parameters > 0) + _propertiesDictionary = new(); + foreach (PropertyInfo pi in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { - // The property is an indexer, skip this. - continue; + int parameters = pi.GetIndexParameters().Length; + if (parameters > 0) + { + // The property is an indexer, skip this. + continue; + } + + _propertiesDictionary.Add(pi.Name, pi.GetValue(this, null)); } - - _propertiesDictionary.Add(pi.Name, pi.GetValue(this, null)); } - + return _propertiesDictionary; } } diff --git a/test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs b/test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs new file mode 100644 index 00000000..44e6b7ec --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using FluentAssertions; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests +{ + public class DynamicClassTest + { + [Fact] + public void GetPropertiesWorks() + { + // Arrange + var range = new List + { + new { FieldName = "TestFieldName", Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.FirstOrDefault(); + + var call = () => item.GetDynamicMemberNames(); + call.Should().NotThrow(); + call.Should().NotThrow(); + } + } +} \ No newline at end of file From 49326aac0505ff77f0a7600e4a4c2f8ced6d2c60 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 23 Oct 2022 11:03:46 +0200 Subject: [PATCH 006/214] Fixed accessing dynamic properties by index (#637) --- src/System.Linq.Dynamic.Core/DynamicClass.cs | 5 +- .../DynamicClassTest.cs | 27 ----- .../DynamicClassTest.cs | 101 ++++++++++++++++++ 3 files changed, 104 insertions(+), 29 deletions(-) delete mode 100644 test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs create mode 100644 test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs diff --git a/src/System.Linq.Dynamic.Core/DynamicClass.cs b/src/System.Linq.Dynamic.Core/DynamicClass.cs index 4498e4e8..5dee90d3 100644 --- a/src/System.Linq.Dynamic.Core/DynamicClass.cs +++ b/src/System.Linq.Dynamic.Core/DynamicClass.cs @@ -18,7 +18,7 @@ namespace System.Linq.Dynamic.Core; /// public abstract class DynamicClass : DynamicObject { - private Dictionary? _propertiesDictionary = null; + private Dictionary? _propertiesDictionary; private Dictionary Properties { @@ -27,6 +27,7 @@ public abstract class DynamicClass : DynamicObject if (_propertiesDictionary == null) { _propertiesDictionary = new(); + foreach (PropertyInfo pi in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { int parameters = pi.GetIndexParameters().Length; @@ -150,7 +151,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object? result) /// /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.) /// - public override bool TrySetMember(SetMemberBinder binder, object value) + public override bool TrySetMember(SetMemberBinder binder, object? value) { string name = binder.Name; if (Properties.ContainsKey(name)) diff --git a/test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs b/test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs deleted file mode 100644 index 44e6b7ec..00000000 --- a/test/System.Linq.Dynamic.Core.Tests.Net6/DynamicClassTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using FluentAssertions; -using Xunit; - -namespace System.Linq.Dynamic.Core.Tests -{ - public class DynamicClassTest - { - [Fact] - public void GetPropertiesWorks() - { - // Arrange - var range = new List - { - new { FieldName = "TestFieldName", Value = 3.14159 } - }; - - // Act - var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); - var item = rangeResult.FirstOrDefault(); - - var call = () => item.GetDynamicMemberNames(); - call.Should().NotThrow(); - call.Should().NotThrow(); - } - } -} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs new file mode 100644 index 00000000..59464287 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using FluentAssertions; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests; + +public class DynamicClassTest +{ + [Fact] + public void DynamicClass_GetProperties_Should_Work() + { + // Arrange + var range = new List + { + new { FieldName = "TestFieldName", Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + var call = () => item.GetDynamicMemberNames(); + call.Should().NotThrow(); + } + + [Fact] + public void DynamicClass_GetPropertyValue_Should_Work() + { + // Arrange + var test = "Test"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + var value = item.FieldName as string; + value.Should().Be(test); + } + + [Fact] + public void DynamicClass_GettingValue_ByIndex_Should_Work() + { + // Arrange + var test = "Test"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + var value = item["FieldName"] as string; + value.Should().Be(test); + } + + [Fact] + public void DynamicClass_SettingExistingPropertyValue_ByIndex_Should_Work() + { + // Arrange + var test = "Test"; + var newTest = "abc"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + item["FieldName"] = newTest; + var value = item["FieldName"] as string; + value.Should().Be(newTest); + } + + [Fact] + public void DynamicClass_SettingNewProperty_ByIndex_Should_Work() + { + // Arrange + var test = "Test"; + var newTest = "abc"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + item["X"] = newTest; + var value = item["X"] as string; + value.Should().Be(newTest); + } +} \ No newline at end of file From ee811919489040b9c9f5521d2427707df53e250d Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 23 Oct 2022 11:10:54 +0200 Subject: [PATCH 007/214] CHANGELOG v1.2.21 --- CHANGELOG.md | 14 ++++++++++++-- Generate-ReleaseNotes.bat | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92131e35..c590159a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,20 @@ +# v1.2.21 (23 October 2022) +- [#627](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/627) - Use PackageIcon + upgrade JetBrains.Annotations [feature] contributed by [StefH](https://github.com/StefH) +- [#630](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/630) - Fix MethodFinder to return topmost implementation of the virtual method [feature] contributed by [jogibear9988](https://github.com/jogibear9988) +- [#631](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/631) - Init field only on first execution [bug] contributed by [BBreiden](https://github.com/BBreiden) +- [#636](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/636) - Fix nullable issues [bug] contributed by [StefH](https://github.com/StefH) +- [#637](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/637) - Fixed accessing dynamic properties by index [bug] contributed by [StefH](https://github.com/StefH) +- [#580](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/580) - C# Expressions use Base Class Virtual Methodinfo [bug] +- [#629](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/629) - Error accessing values in DynamicClass - fails on second attempt [bug] +- [#634](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/634) - After Upgrade NuGet-Package to 1.2.20 accessing dynamic properties by index fails [bug] +- [#635](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/635) - Compile errors due to missing nullable reference annotations on APIs that accept null [bug] + # v1.2.20 (03 September 2022) - [#619](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/619) - Fix generic comparer type [bug] contributed by [StefH](https://github.com/StefH) - [#620](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/620) - ToDynamicListAsync uses IAsyncEnumerable (if applicable) [feature] contributed by [StefH](https://github.com/StefH) - [#622](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/622) - Add unit tests for "As acting on property" [feature, test] contributed by [StefH](https://github.com/StefH) - [#625](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/625) - Add unit test for Where with empty string [test] contributed by [StefH](https://github.com/StefH) -- [#616](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/616) - Example in Documentation is not working in Blazor Server: Expression with DateTime -- [#617](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/617) - "Failed to compare two elements in the array." System.InvalidOperationException (V1.2.19 compared to V1.2.18) +- [#617](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/617) - "Failed to compare two elements in the array." System.InvalidOperationException (V1.2.19 compared to V1.2.18) [feature] # v1.2.19 (26 June 2022) - [#579](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/579) - Support Struct for DynamicLinqTypeAttribute [feature] contributed by [StefH](https://github.com/StefH) diff --git a/Generate-ReleaseNotes.bat b/Generate-ReleaseNotes.bat index 4b41d448..f7f9d174 100644 --- a/Generate-ReleaseNotes.bat +++ b/Generate-ReleaseNotes.bat @@ -1,5 +1,5 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=v1.2.20 +SET version=v1.2.21 GitHubReleaseNotes --output CHANGELOG.md --exclude-labels invalid question documentation wontfix --language en --version %version% --token %GH_TOKEN% From d0a3d9a55dd8c6ee661c8614bb63de7facb3099e Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 23 Oct 2022 11:33:03 +0200 Subject: [PATCH 008/214] Fix build+tests for nullable & namespace --- Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj | 2 +- .../EntityFramework.DynamicLinq.csproj | 1 + ...tyFrameworkCore.DynamicLinq.EFCore2.csproj | 1 + ...tyFrameworkCore.DynamicLinq.EFCore3.csproj | 1 + ...tyFrameworkCore.DynamicLinq.EFCore5.csproj | 1 + ...EntityFramework.Classic.DynamicLinq.csproj | 1 + .../EntityFramework.DynamicLinq.Tests.csproj | 1 + ...System.Linq.Dynamic.Core.Tests.Net5.csproj | 1 + .../DynamicClassTest.cs | 177 +++++++++--------- .../Parser/MethodFinderTest.cs | 13 +- 10 files changed, 100 insertions(+), 99 deletions(-) diff --git a/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj b/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj index 0f686a55..cf52b2cb 100644 --- a/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj +++ b/Z.Dynamic.Core.Lab/Z.Dynamic.Core.Lab.csproj @@ -14,4 +14,4 @@ - + \ No newline at end of file diff --git a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj index e9105fdc..822f6203 100644 --- a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj +++ b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj @@ -10,6 +10,7 @@ system;linq;dynamic;entityframework;core;async {D3804228-91F4-4502-9595-39584E510000} net45;net452;net46;netstandard2.1 + 10 1.2.$(PatchVersion) diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj index 6537b112..efc6f5cb 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj @@ -10,6 +10,7 @@ system;linq;dynamic;entityframework;core;async {D3804228-91F4-4502-9595-39584E510001} netstandard2.0 + 10 2.2.$(PatchVersion) diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj index e2e34391..8c5f1fbc 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj @@ -10,6 +10,7 @@ system;linq;dynamic;entityframework;core;async {7994FECC-965C-4A5D-8B0E-1A6EA769D4BE} netstandard2.0 + 10 3.2.$(PatchVersion) diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj index c879d151..57204bb5 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj @@ -10,6 +10,7 @@ system;linq;dynamic;entityframework;core;async {D3804228-91F4-4502-9595-39584E519901} netstandard2.1;net5.0 + 10 5.2.$(PatchVersion) diff --git a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj index 88fd58ce..3d24ab88 100644 --- a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj +++ b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj @@ -10,6 +10,7 @@ system;linq;dynamic;Z.EntityFramework;core;async;classic {D3804228-91F4-4502-9595-39584Ea20000} net45;netstandard2.0 + 10 1.2.$(PatchVersion) diff --git a/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj b/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj index 6be64777..2b92aadc 100644 --- a/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj +++ b/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj @@ -3,6 +3,7 @@ Stef Heyenrath net461 + 10 EF;NET461 EntityFramework.DynamicLinq.Tests EntityFramework.DynamicLinq.Tests diff --git a/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj b/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj index 6f3f1075..7a75b825 100644 --- a/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj +++ b/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj @@ -2,6 +2,7 @@ net5.0 + 10 System.Linq.Dynamic.Core.Tests full True diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs index 59464287..e8b5b463 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs @@ -2,100 +2,101 @@ using FluentAssertions; using Xunit; -namespace System.Linq.Dynamic.Core.Tests; - -public class DynamicClassTest +namespace System.Linq.Dynamic.Core.Tests { - [Fact] - public void DynamicClass_GetProperties_Should_Work() + public class DynamicClassTest { - // Arrange - var range = new List + [Fact] + public void DynamicClass_GetProperties_Should_Work() { - new { FieldName = "TestFieldName", Value = 3.14159 } - }; - - // Act - var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); - var item = rangeResult.First(); - - var call = () => item.GetDynamicMemberNames(); - call.Should().NotThrow(); - } - - [Fact] - public void DynamicClass_GetPropertyValue_Should_Work() - { - // Arrange - var test = "Test"; - var range = new List + // Arrange + var range = new List + { + new { FieldName = "TestFieldName", Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + var call = () => item.GetDynamicMemberNames(); + call.Should().NotThrow(); + } + + [Fact] + public void DynamicClass_GetPropertyValue_Should_Work() { - new { FieldName = test, Value = 3.14159 } - }; - - // Act - var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); - var item = rangeResult.First(); - - var value = item.FieldName as string; - value.Should().Be(test); - } - - [Fact] - public void DynamicClass_GettingValue_ByIndex_Should_Work() - { - // Arrange - var test = "Test"; - var range = new List + // Arrange + var test = "Test"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + var value = item.FieldName as string; + value.Should().Be(test); + } + + [Fact] + public void DynamicClass_GettingValue_ByIndex_Should_Work() { - new { FieldName = test, Value = 3.14159 } - }; - - // Act - var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); - var item = rangeResult.First(); - - var value = item["FieldName"] as string; - value.Should().Be(test); - } - - [Fact] - public void DynamicClass_SettingExistingPropertyValue_ByIndex_Should_Work() - { - // Arrange - var test = "Test"; - var newTest = "abc"; - var range = new List + // Arrange + var test = "Test"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + var value = item["FieldName"] as string; + value.Should().Be(test); + } + + [Fact] + public void DynamicClass_SettingExistingPropertyValue_ByIndex_Should_Work() { - new { FieldName = test, Value = 3.14159 } - }; - - // Act - var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); - var item = rangeResult.First(); - - item["FieldName"] = newTest; - var value = item["FieldName"] as string; - value.Should().Be(newTest); - } - - [Fact] - public void DynamicClass_SettingNewProperty_ByIndex_Should_Work() - { - // Arrange - var test = "Test"; - var newTest = "abc"; - var range = new List + // Arrange + var test = "Test"; + var newTest = "abc"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + item["FieldName"] = newTest; + var value = item["FieldName"] as string; + value.Should().Be(newTest); + } + + [Fact] + public void DynamicClass_SettingNewProperty_ByIndex_Should_Work() { - new { FieldName = test, Value = 3.14159 } - }; - - // Act - var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); - var item = rangeResult.First(); - - item["X"] = newTest; - var value = item["X"] as string; - value.Should().Be(newTest); + // Arrange + var test = "Test"; + var newTest = "abc"; + var range = new List + { + new { FieldName = test, Value = 3.14159 } + }; + + // Act + var rangeResult = range.AsQueryable().Select("new(FieldName as FieldName)").ToDynamicList(); + var item = rangeResult.First(); + + item["X"] = newTest; + var value = item["X"] as string; + value.Should().Be(newTest); + } } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs index 91b9d655..16564d94 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/MethodFinderTest.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Linq.Dynamic.Core.Parser; using System.Linq.Expressions; -using static System.Console; -using static System.Linq.Expressions.Expression; -using System.Linq.Dynamic.Core.Parser; -using System.Linq.Dynamic.Core; using Xunit; +using static System.Linq.Expressions.Expression; namespace System.Linq.Dynamic.Core.Tests.Parser { @@ -27,4 +20,4 @@ public void MethodsOfDynamicLinqAndSystemLinqShouldBeEqual() Assert.Equal(((MethodCallExpression)expr.Body).Method.DeclaringType, ((MethodCallExpression)expr1).Method.DeclaringType); } } -} +} \ No newline at end of file From 72c4c1cd7e1b16249fed5ed85d2c8126ddbd36da Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 28 Oct 2022 14:23:15 +0200 Subject: [PATCH 009/214] Add unit test for DynamicClass SerializeToJson (#641) --- .../DynamicClassTest.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs index e8b5b463..da3f5c29 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicClassTest.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.Xml.Linq; using FluentAssertions; +using Newtonsoft.Json; using Xunit; namespace System.Linq.Dynamic.Core.Tests @@ -98,5 +100,27 @@ public void DynamicClass_SettingNewProperty_ByIndex_Should_Work() var value = item["X"] as string; value.Should().Be(newTest); } + + [Fact] + public void DynamicClass_SerializeToJson_Should_Work() + { + // Arrange + var props = new[] + { + new DynamicProperty("Name", typeof(string)), + new DynamicProperty("Birthday", typeof(DateTime)) + }; + var type = DynamicClassFactory.CreateType(props); + + var dynamicClass = (DynamicClass) Activator.CreateInstance(type); + dynamicClass.SetDynamicPropertyValue("Name", "Albert"); + dynamicClass.SetDynamicPropertyValue("Birthday", new DateTime(1879, 3, 14)); + + // Act + var json = JsonConvert.SerializeObject(dynamicClass); + + // Assert + json.Should().Be("{\"Name\":\"Albert\",\"Birthday\":\"1879-03-14T00:00:00\"}"); + } } } \ No newline at end of file From c27ebb7621ba2b47013a31e4e5df9f589b5e7929 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 28 Oct 2022 17:56:55 +0200 Subject: [PATCH 010/214] v1.2.21 --- CHANGELOG.md | 5 +++-- System.Linq.Dynamic.Core.sln | 1 + version.xml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c590159a..d7cf5aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,15 @@ -# v1.2.21 (23 October 2022) +# v1.2.21 (28 October 2022) - [#627](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/627) - Use PackageIcon + upgrade JetBrains.Annotations [feature] contributed by [StefH](https://github.com/StefH) - [#630](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/630) - Fix MethodFinder to return topmost implementation of the virtual method [feature] contributed by [jogibear9988](https://github.com/jogibear9988) - [#631](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/631) - Init field only on first execution [bug] contributed by [BBreiden](https://github.com/BBreiden) - [#636](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/636) - Fix nullable issues [bug] contributed by [StefH](https://github.com/StefH) - [#637](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/637) - Fixed accessing dynamic properties by index [bug] contributed by [StefH](https://github.com/StefH) +- [#641](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/641) - Add unit test for DynamicClass SerializeToJson [feature] contributed by [StefH](https://github.com/StefH) - [#580](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/580) - C# Expressions use Base Class Virtual Methodinfo [bug] - [#629](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/629) - Error accessing values in DynamicClass - fails on second attempt [bug] - [#634](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/634) - After Upgrade NuGet-Package to 1.2.20 accessing dynamic properties by index fails [bug] - [#635](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/635) - Compile errors due to missing nullable reference annotations on APIs that accept null [bug] +- [#640](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/640) - NullReferenceException during json serialize of DynamicClass [bug] # v1.2.20 (03 September 2022) - [#619](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/619) - Fix generic comparer type [bug] contributed by [StefH](https://github.com/StefH) @@ -30,7 +32,6 @@ - [#612](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/612) - Update dependencies (Newtonsoft.Json and more) [dependencies] contributed by [StefH](https://github.com/StefH) - [#511](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/511) - Strange SelectMany behaviour using JSON [bug] - [#548](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/548) - IComparer<T> not supported for OrderBy? [feature] -- [#565](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/565) - Methods such as `OrderBy` may not be calling the correct method of the Provider. - [#581](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/581) - ConsoleApp_netcore2.1_EF2.1.1 fails to run with exception [bug] - [#586](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/586) - Parenthesis around an "In" expression raise an exception [bug] diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln index 5f3c9303..5361e277 100644 --- a/System.Linq.Dynamic.Core.sln +++ b/System.Linq.Dynamic.Core.sln @@ -22,6 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NuGet.txt = NuGet.txt README.md = README.md report\run-coverlet-local.cmd = report\run-coverlet-local.cmd + version.xml = version.xml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFramework.DynamicLinq.Tests.net452", "test\EntityFramework.DynamicLinq.Tests.net452\EntityFramework.DynamicLinq.Tests.net452.csproj", "{6B45E89C-0788-4942-924F-EF6397114BD1}" diff --git a/version.xml b/version.xml index 640df83f..726bbb77 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 21-preview-01 + 21 From bdc1ec67aadb86b962fecfd413c17e7ce57b71bc Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 5 Nov 2022 13:16:35 +0100 Subject: [PATCH 011/214] Rename extension method "AsEnumerable" to "AsDynamicEnumerable". (#642) --- .../DynamicQueryableExtensions.cs | 8 ++++---- test/System.Linq.Dynamic.Core.Tests/ComplexTests.cs | 4 ++-- test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs | 4 ++-- .../QueryableTests.Select.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index a9a72943..fb57326b 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -281,21 +281,21 @@ public static double Average(this IQueryable source, LambdaExpression lambda) } #endregion Average - #region AsEnumerable + #region AsDynamicEnumerable #if NET35 /// /// Returns the input typed as of ./> /// /// The sequence to type as of . /// The input typed as of . - public static IEnumerable AsEnumerable(this IQueryable source) + public static IEnumerable AsDynamicEnumerable(this IQueryable source) #else /// /// Returns the input typed as of dynamic. /// /// The sequence to type as of dynamic. /// The input typed as of dynamic. - public static IEnumerable AsEnumerable(this IQueryable source) + public static IEnumerable AsDynamicEnumerable(this IQueryable source) #endif { foreach (var obj in source) @@ -303,7 +303,7 @@ public static IEnumerable AsEnumerable(this IQueryable source) yield return obj; } } - #endregion AsEnumerable + #endregion AsDynamicEnumerable #region Cast private static readonly MethodInfo _cast = QueryableMethodFinder.GetGenericMethod(nameof(Queryable.Cast)); diff --git a/test/System.Linq.Dynamic.Core.Tests/ComplexTests.cs b/test/System.Linq.Dynamic.Core.Tests/ComplexTests.cs index 32f63e68..78b0de00 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ComplexTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ComplexTests.cs @@ -111,11 +111,11 @@ public void GroupByAndSelect_TestDynamicSelectMember() #else Assert.Equal( realQry.Select(x => x.Age).ToArray(), - selectQry.AsEnumerable().Select(x => x.Age).Cast().ToArray()); + selectQry.AsDynamicEnumerable().Select(x => x.Age).Cast().ToArray()); Assert.Equal( realQry.Select(x => x.TotalIncome).ToArray(), - selectQry.AsEnumerable().Select(x => x.TotalIncome).Cast().ToArray()); + selectQry.AsDynamicEnumerable().Select(x => x.TotalIncome).Cast().ToArray()); #endif } } diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index e5f248ef..d56c829e 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -2180,7 +2180,7 @@ public void ExpressionTests_Sum() var qry = initValues.AsQueryable().Select(x => new { strValue = "str", intValue = x }).GroupBy(x => x.strValue); // Act - var result = qry.Select("Sum(intValue)").AsEnumerable().ToArray()[0]; + var result = qry.Select("Sum(intValue)").AsDynamicEnumerable().ToArray()[0]; // Assert Assert.Equal(15, result); @@ -2194,7 +2194,7 @@ public void ExpressionTests_Sum_LowerCase() var qry = initValues.AsQueryable().Select(x => new { strValue = "str", intValue = x }).GroupBy(x => x.strValue); // Act - var result = qry.Select("sum(intValue)").AsEnumerable().ToArray()[0]; + var result = qry.Select("sum(intValue)").AsDynamicEnumerable().ToArray()[0]; // Assert Assert.Equal(15, result); diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index 65c87882..3cee3607 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -142,7 +142,7 @@ public void Select_Dynamic3() Assert.Equal(testList.Select(x => x.UserName).ToArray(), userNames.Cast().ToArray()); Assert.Equal( testList.Select(x => "{ UserName = " + x.UserName + ", MyFirstName = " + x.Profile.FirstName + " }").ToArray(), - userFirstName.AsEnumerable().Select(x => x.ToString()).Cast().ToArray()); + userFirstName.AsDynamicEnumerable().Select(x => x.ToString()).Cast().ToArray()); Assert.Equal(testList[0].Roles.Select(x => x.Id).ToArray(), Enumerable.ToArray(userRoles.First().RoleIds)); #endif } From c838600d967f1deb2df65262764e4f48c12e531c Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 6 Nov 2022 13:33:24 +0100 Subject: [PATCH 012/214] v1.2.22 --- CHANGELOG.md | 4 ++++ Generate-ReleaseNotes.bat | 2 +- version.xml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7cf5aa4..203ce5df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.2.22 (06 November 2022) +- [#642](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/642) - Rename extension method "AsEnumerable" to "AsDynamicEnumerable". [feature] contributed by [StefH](https://github.com/StefH) +- [#304](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/304) - System.Linq.Dynamic.Core.DynamicQueryableExtensions.AsEnumerable conflicts with System.Linq.Enumerable.AsEnumerable [bug] + # v1.2.21 (28 October 2022) - [#627](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/627) - Use PackageIcon + upgrade JetBrains.Annotations [feature] contributed by [StefH](https://github.com/StefH) - [#630](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/630) - Fix MethodFinder to return topmost implementation of the virtual method [feature] contributed by [jogibear9988](https://github.com/jogibear9988) diff --git a/Generate-ReleaseNotes.bat b/Generate-ReleaseNotes.bat index f7f9d174..556a7098 100644 --- a/Generate-ReleaseNotes.bat +++ b/Generate-ReleaseNotes.bat @@ -1,5 +1,5 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=v1.2.21 +SET version=v1.2.22 GitHubReleaseNotes --output CHANGELOG.md --exclude-labels invalid question documentation wontfix --language en --version %version% --token %GH_TOKEN% diff --git a/version.xml b/version.xml index 726bbb77..0c947aa0 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 21 + 22 From 3afe58a2cf0287796dcd1980688181a08d1bce7e Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 12 Nov 2022 10:07:48 +0100 Subject: [PATCH 013/214] Add support for .NET 7 and EF Core 7 (#644) * Add NuGet which support Microsoft.EntityFrameworkCore 7.0.0 * 7 * ci * ci * fix test * net6.0 * setup * 5.0.x * ... * LinqKit --- .github/workflows/ci.yml | 24 ++++++-- System.Linq.Dynamic.Core.sln | 38 +++++++++++++ .../ConsoleApp_net40_sqlite_original.csproj | 2 +- .../Program.cs | 4 +- .../packages.config | 2 +- .../EntityFramework.DynamicLinq.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore2.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore3.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore5.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore6.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore7.csproj | 48 ++++++++++++++++ .../Properties/AssemblyInfo.cs | 6 ++ .../System.Linq.Dynamic.Core.csproj | 8 +-- ...EntityFramework.Classic.DynamicLinq.csproj | 2 +- ...System.Linq.Dynamic.Core.Tests.Net5.csproj | 16 +++--- ...System.Linq.Dynamic.Core.Tests.Net6.csproj | 18 +++--- ...System.Linq.Dynamic.Core.Tests.Net7.csproj | 57 +++++++++++++++++++ .../QueryableTests.GroupBy.cs | 6 +- .../QueryableTests.Select.cs | 2 +- .../QueryableTests.Where.cs | 2 +- version.xml | 2 +- 21 files changed, 204 insertions(+), 43 deletions(-) create mode 100644 src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7.csproj create mode 100644 src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Properties/AssemblyInfo.cs create mode 100644 test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e62bf53..9f9105da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,23 +8,35 @@ jobs: steps: - uses: actions/checkout@v2 + + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: '6.0.x' + + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: '7.0.x' - name: Build Projects run: | dotnet build ./src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj -c Release -p:buildType=azure-pipelines-ci - - name: Run Tests net6.0 + - name: Run Tests net7.0 run: | - dotnet test ./test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj -c Release -p:buildType=azure-pipelines-ci + dotnet build ./test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj -c Release -p:buildType=azure-pipelines-ci + dotnet test ./test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj -c Release -p:buildType=azure-pipelines-ci --no-build - - name: Run Tests net5.0 + - name: Run Tests net6.0 run: | - dotnet test ./test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj -c Release -p:buildType=azure-pipelines-ci + dotnet build ./test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj -c Release -p:buildType=azure-pipelines-ci + dotnet test ./test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj -c Release -p:buildType=azure-pipelines-ci --no-build - name: Run Tests netcoreapp31 run: | - dotnet test ./test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj -c Release -f netcoreapp31 -p:buildType=azure-pipelines-ci + dotnet build ./test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj -c Release -f netcoreapp31 -p:buildType=azure-pipelines-ci + dotnet test ./test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj -c Release -f netcoreapp31 -p:buildType=azure-pipelines-ci --no-build - name: Run Tests net452 run: | - dotnet test ./test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj -c Release -f net452 -p:buildType=azure-pipelines-ci + dotnet build ./test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj -c Release -f net452 -p:buildType=azure-pipelines-ci + dotnet test ./test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj -c Release -f net452 -p:buildType=azure-pipelines-ci --no-build diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln index 5361e277..232ced2e 100644 --- a/System.Linq.Dynamic.Core.sln +++ b/System.Linq.Dynamic.Core.sln @@ -127,6 +127,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.Te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAppServer", "src-blazor\BlazorAppServer\BlazorAppServer.csproj", "{B133DA55-339D-4600-AED3-46214AD9F08A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7", "src\Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7\Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7.csproj", "{FB2F4C99-EC34-4D29-87E2-944B25D90EF7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.Tests.Net7", "test\System.Linq.Dynamic.Core.Tests.Net7\System.Linq.Dynamic.Core.Tests.Net7.csproj", "{CC63ECEB-18C1-462B-BAFC-7F146A7C2740}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -765,6 +769,38 @@ Global {B133DA55-339D-4600-AED3-46214AD9F08A}.Release|x64.Build.0 = Release|Any CPU {B133DA55-339D-4600-AED3-46214AD9F08A}.Release|x86.ActiveCfg = Release|Any CPU {B133DA55-339D-4600-AED3-46214AD9F08A}.Release|x86.Build.0 = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|ARM.ActiveCfg = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|ARM.Build.0 = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|x64.ActiveCfg = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|x64.Build.0 = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|x86.ActiveCfg = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Debug|x86.Build.0 = Debug|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|Any CPU.Build.0 = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|ARM.ActiveCfg = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|ARM.Build.0 = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|x64.ActiveCfg = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|x64.Build.0 = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|x86.ActiveCfg = Release|Any CPU + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7}.Release|x86.Build.0 = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|ARM.Build.0 = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|x64.ActiveCfg = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|x64.Build.0 = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|x86.ActiveCfg = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Debug|x86.Build.0 = Debug|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|Any CPU.Build.0 = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|ARM.ActiveCfg = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|ARM.Build.0 = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|x64.ActiveCfg = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|x64.Build.0 = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|x86.ActiveCfg = Release|Any CPU + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -809,6 +845,8 @@ Global {2AC8773A-FCDD-4613-8758-E45E5F10CA3A} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38} {EDAB46DA-7079-42D7-819D-1932C542872F} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38} {B133DA55-339D-4600-AED3-46214AD9F08A} = {122BC4FA-7563-4E35-9D17-077F16F1629F} + {FB2F4C99-EC34-4D29-87E2-944B25D90EF7} = {DBD7D9B6-FCC7-4650-91AF-E6457573A68F} + {CC63ECEB-18C1-462B-BAFC-7F146A7C2740} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {94C56722-194E-4B8B-BC23-B3F754E89A20} diff --git a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj index e07a4f74..8c2eddaa 100644 --- a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj +++ b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/ConsoleApp_net40_sqlite_original.csproj @@ -46,7 +46,7 @@ True - ..\..\packages\JetBrains.Annotations.2022.1.0\lib\net20\JetBrains.Annotations.dll + ..\..\packages\JetBrains.Annotations.2022.3.1\lib\net20\JetBrains.Annotations.dll ..\..\packages\SQLite.CodeFirst.1.3.0.17\lib\net40\SQLite.CodeFirst.dll diff --git a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/Program.cs b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/Program.cs index fe4381cd..c6567e5c 100644 --- a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/Program.cs +++ b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/Program.cs @@ -150,7 +150,7 @@ public static void ExpressionTests_Sum() var qry = initValues.AsQueryable().Select(x => new { strValue = "str", intValue = x }).GroupBy(x => x.strValue); //Act - var result = qry.Select("Sum(intValue)").AsEnumerable().ToArray()[0]; + var result = qry.Select("Sum(intValue)").AsDynamicEnumerable().ToArray()[0]; //Assert Write(15, result); @@ -173,7 +173,7 @@ public static void Select() //Assert WriteArray(range.Select(x => x * x).ToArray(), rangeResult.Cast().ToArray()); WriteArray(testList.Select(x => x.UserName).ToArray(), userNames.ToDynamicArray()); - WriteArray(testList.Select(x => "{UserName=" + x.UserName + ", MyFirstName=" + x.Profile.FirstName + "}").ToArray(), userFirstName.AsEnumerable().Select(x => x.ToString()).ToArray()); + WriteArray(testList.Select(x => "{UserName=" + x.UserName + ", MyFirstName=" + x.Profile.FirstName + "}").ToArray(), userFirstName.AsDynamicEnumerable().Select(x => x.ToString()).ToArray()); Guid[] check = testList[0].Roles.Select(x => x.Id).ToArray(); //dynamic f = userRoles.First(); diff --git a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config index fef02f4e..8f6e93ff 100644 --- a/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config +++ b/src-console/System.Linq.Dynamic.Core.ConsoleTestApp.net40/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj index 822f6203..e3c684a9 100644 --- a/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj +++ b/src/EntityFramework.DynamicLinq/EntityFramework.DynamicLinq.csproj @@ -36,7 +36,7 @@ - + diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj index efc6f5cb..4cd64a1c 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2.csproj @@ -40,7 +40,7 @@ - + diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj index 8c5f1fbc..49c265d1 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3.csproj @@ -42,7 +42,7 @@ - + diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj index 57204bb5..d98e4daf 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore5.csproj @@ -43,7 +43,7 @@ - + \ No newline at end of file diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj index 03f1ce55..1023f329 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore6.csproj @@ -42,7 +42,7 @@ - + \ No newline at end of file diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7.csproj b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7.csproj new file mode 100644 index 00000000..8284788d --- /dev/null +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7.csproj @@ -0,0 +1,48 @@ + + + + + Microsoft.EntityFrameworkCore.DynamicLinq + ../Microsoft.EntityFrameworkCore.DynamicLinq.EFCore2/Microsoft.EntityFrameworkCore.DynamicLinq.snk + Microsoft.EntityFrameworkCore.DynamicLinq + $(DefineConstants);EFCORE;EFCORE_3X;EFDYNAMICFUNCTIONS;ASYNCENUMERABLE + Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support + system;linq;dynamic;entityframework;core;async + {FB2F4C99-EC34-4D29-87E2-944B25D90ef7} + net6.0;net7.0 + 7.2.$(PatchVersion) + + + + full + + + + + portable + true + + + + net6.0;net7.0 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Properties/AssemblyInfo.cs b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..54dd50af --- /dev/null +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore7/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +using System.Runtime.InteropServices; + +[assembly: ComVisible(false)] +#if !(WINDOWS_APP || NETSTANDARD2_1) +[assembly: Guid("b467c675-c014-4b55-85b9-9578941d2ef7")] +#endif diff --git a/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj b/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj index 0d06a5e7..55f55438 100644 --- a/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj +++ b/src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.csproj @@ -9,7 +9,7 @@ This is a .NETStandard / .NET Core port of the the Microsoft assembly for the .Net 4.0 Dynamic language functionality. system;linq;dynamic;core;dotnet;NETCoreApp;NETStandard {D3804228-91F4-4502-9595-39584E510002} - net35;net40;net45;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;uap10.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0 + net35;net40;net45;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;uap10.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net7.0 1.2.$(PatchVersion) @@ -26,14 +26,14 @@ - net40;net45;net46;netstandard1.3;netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0 + net40;net45;net46;netstandard1.3;netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net7.0 $(DefineConstants);NETSTANDARD - + $(DefineConstants);ASYNCENUMERABLE @@ -59,7 +59,7 @@ - + diff --git a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj index 3d24ab88..b6f534b0 100644 --- a/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj +++ b/src/Z.EntityFramework.Classic.DynamicLinq/Z.EntityFramework.Classic.DynamicLinq.csproj @@ -36,7 +36,7 @@ - + \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj b/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj index 7a75b825..36e8bac4 100644 --- a/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj +++ b/test/System.Linq.Dynamic.Core.Tests.Net5/System.Linq.Dynamic.Core.Tests.Net5.csproj @@ -12,13 +12,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -26,15 +26,15 @@ - - + + - - + + diff --git a/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj b/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj index 84e96058..9ac38766 100644 --- a/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj +++ b/test/System.Linq.Dynamic.Core.Tests.Net6/System.Linq.Dynamic.Core.Tests.Net6.csproj @@ -12,17 +12,17 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -30,15 +30,15 @@ - - + + - - + + diff --git a/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj b/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj new file mode 100644 index 00000000..90dcec95 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj @@ -0,0 +1,57 @@ + + + + net7.0 + System.Linq.Dynamic.Core.Tests + full + True + ../../src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.snk + false + + $(DefineConstants);NETCOREAPP;EFCORE;EFCORE_3X;NETCOREAPP3_1 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs index 6bd3ce0e..55b9a1af 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs @@ -41,7 +41,7 @@ public void GroupBy_Dynamic_NullableDateTime() var qry = new[] { new DateTime(2020, 1, 1), (DateTime?)null }.AsQueryable(); // Act - var byYear = qry.GroupBy("np(Value.Year, 2019)"); + var byYear = qry.GroupBy("np(Value.Year, 2019)").ToDynamicArray(); // Assert byYear.Should().HaveCount(2); @@ -58,7 +58,7 @@ public void GroupBy_Dynamic_NullableDateTime_2Levels() }.AsQueryable(); // Act - var byYear = qry.GroupBy("np(Test.D.Value.Year, 2019)"); + var byYear = qry.GroupBy("np(Test.D.Value.Year, 2019)").ToDynamicArray(); // Assert byYear.Should().HaveCount(2); @@ -75,7 +75,7 @@ public void GroupBy_Dynamic_NullableDateTime_3Levels() }.AsQueryable(); // Act - var byYear = qry.GroupBy("np(Test.Test.D.Value.Year, 2019)"); + var byYear = qry.GroupBy("np(Test.Test.D.Value.Year, 2019)").ToDynamicArray(); // Assert byYear.Should().HaveCount(2); diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index 3cee3607..ee365db3 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -412,7 +412,7 @@ public void Select_Dynamic_RenameParameterExpression_Is_True() Check.That(result).Equals("System.Int32[].Select(it => (it * it))"); } -#if NET452 || NET5_0 || NET6_0 +#if NET452 || NET5_0 || NET6_0 || NET7_0 [Fact(Skip = "Fails sometimes in GitHub CI build")] #else [Fact] diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs index d9b9cea2..6ce39e54 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs @@ -115,7 +115,7 @@ public void Where_Dynamic_IQueryable_LambdaExpression() LambdaExpression lambdaExpression = userExpression; // Act - var result = queryable.Where(lambdaExpression); + var result = queryable.Where(lambdaExpression).ToDynamicArray(); // Assert result.Should().HaveCount(1); diff --git a/version.xml b/version.xml index 0c947aa0..165a71ac 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 22 + 23 From e470f2476fd33a9c18a6187e595b846562e12342 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 12 Nov 2022 10:14:51 +0100 Subject: [PATCH 014/214] v1.2.23 --- CHANGELOG.md | 3 +++ Generate-ReleaseNotes.bat | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 203ce5df..1d177df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# v1.2.23 (12 November 2022) +- [#644](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/644) - Add support for .NET 7 and EF Core 7 [feature] contributed by [StefH](https://github.com/StefH) + # v1.2.22 (06 November 2022) - [#642](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/642) - Rename extension method "AsEnumerable" to "AsDynamicEnumerable". [feature] contributed by [StefH](https://github.com/StefH) - [#304](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/304) - System.Linq.Dynamic.Core.DynamicQueryableExtensions.AsEnumerable conflicts with System.Linq.Enumerable.AsEnumerable [bug] diff --git a/Generate-ReleaseNotes.bat b/Generate-ReleaseNotes.bat index 556a7098..4d61cd78 100644 --- a/Generate-ReleaseNotes.bat +++ b/Generate-ReleaseNotes.bat @@ -1,5 +1,5 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=v1.2.22 +SET version=v1.2.23 GitHubReleaseNotes --output CHANGELOG.md --exclude-labels invalid question documentation wontfix --language en --version %version% --token %GH_TOKEN% From 8224f13a414f6ed3c3671df6c0b4dbe8f487ee64 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Thu, 17 Nov 2022 10:42:32 +0100 Subject: [PATCH 015/214] Add more unittests for issue 645 (#646) --- .../Parser/ConstantExpressionWrapper.cs | 4 +- .../Parser/TypeHelper.cs | 3 + .../DynamicExpressionParserTests.cs | 85 +++++++++++++++++-- .../Helpers/Models/Person.cs | 8 +- 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs index 87bc836a..7b3e403b 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs @@ -193,7 +193,7 @@ private static MemberExpression WrappedConstant(TValue value) { var wrapper = new WrappedValue(value); - return Expression.Property(Expression.Constant(wrapper), typeof(WrappedValue).GetProperty("Value")); + return Expression.Property(Expression.Constant(wrapper), typeof(WrappedValue).GetProperty("Value")!); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index 30a591cf..bdf56d72 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -186,10 +186,12 @@ public static bool IsCompatibleWith(Type source, Type target) { return true; } + if (!target.GetTypeInfo().IsValueType) { return target.IsAssignableFrom(source); } + Type st = GetNonNullableType(source); Type tt = GetNonNullableType(target); @@ -197,6 +199,7 @@ public static bool IsCompatibleWith(Type source, Type target) { return false; } + Type sc = st.GetTypeInfo().IsEnum ? typeof(object) : st; Type tc = tt.GetTypeInfo().IsEnum ? typeof(object) : tt; diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index d1064e3f..342182a6 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -279,7 +279,7 @@ public Type ResolveTypeBySimpleName(string typeName) } [Fact] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false() + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false_String() { // Assign var config = new ParsingConfig @@ -291,14 +291,33 @@ public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQu var expression = DynamicExpressionParser.ParseLambda(config, true, "s => s == \"x\""); // Assert - dynamic constantExpression = (ConstantExpression)(expression.Body as BinaryExpression).Right; - string value = constantExpression.Value; + ConstantExpression constantExpression = (ConstantExpression)((BinaryExpression)expression.Body).Right; + object value = constantExpression.Value; Check.That(value).IsEqualTo("x"); } [Fact] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true() + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false_DateTime() + { + // Assign + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = false + }; + + // Act + var expression = DynamicExpressionParser.ParseLambda(config, true, "D == \"2022-03-02\""); + + // Assert + ConstantExpression constantExpression = (ConstantExpression)((BinaryExpression)expression.Body).Right; + object value = constantExpression.Value; + + Check.That(value).IsEqualTo(new DateTime(2022, 3, 2)); + } + + [Fact] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true_Int() { // Assign var config = new ParsingConfig @@ -311,17 +330,42 @@ public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQu var expressionAsString = expression.ToString(); // Assert - Check.That(expressionAsString).IsEqualTo("Param_0 => (Param_0.Id == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.Int32]).Value)"); + expressionAsString.Should().Be("Param_0 => (Param_0.Id == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.Int32]).Value)"); - dynamic constantExpression = ((MemberExpression)(expression.Body as BinaryExpression).Right).Expression as ConstantExpression; - var wrappedObj = constantExpression.Value; + ConstantExpression constantExpression = (ConstantExpression)((MemberExpression)((BinaryExpression)expression.Body).Right).Expression; + var wrappedObj = constantExpression!.Value; - var propertyInfo = wrappedObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); - var value = (int)propertyInfo.GetValue(wrappedObj); + PropertyInfo propertyInfo = wrappedObj!.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); + object value = propertyInfo!.GetValue(wrappedObj); Check.That(value).IsEqualTo(42); } + [Fact(Skip = "Issue 645")] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true_DateTime() + { + // Assign + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var expression = DynamicExpressionParser.ParseLambda(config, false, "D = \"2022-11-16\""); + var expressionAsString = expression.ToString(); + + // Assert + expressionAsString.Should().Be("Param_0 => (Param_0.D == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.DateTime]).Value)"); + + ConstantExpression constantExpression = (ConstantExpression)((MemberExpression)((BinaryExpression)expression.Body).Right).Expression; + var wrappedObj = constantExpression!.Value; + + PropertyInfo propertyInfo = wrappedObj!.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); + object value = propertyInfo!.GetValue(wrappedObj); + + Check.That(value).IsEqualTo(new DateTime(2022, 11, 16)); + } + [Theory] [InlineData("NullableIntValue", "42")] [InlineData("NullableDoubleValue", "42.23")] @@ -1013,6 +1057,29 @@ public void DynamicExpressionParser_ParseLambda_With_Null_Equals_Guid() Assert.True(result); } + [Fact] + public void DynamicExpressionParser_ParseLambda_With_DateTime_Equals_String() + { + // Arrange + var someDateTime = "2022-03-02"; + var user = new Person + { + D = new DateTime(2022, 3, 2) + }; + var expressionText = $"D == \"{someDateTime}\""; + + // Act + var lambda = DynamicExpressionParser.ParseLambda(typeof(Person), null, expressionText, user); + var dtLambda = lambda as Expression>; + Assert.NotNull(dtLambda); + + var del = lambda.Compile(); + var result = (bool)del.DynamicInvoke(user); + + // Assert + Assert.True(result); + } + [Fact] public void DynamicExpressionParser_ParseLambda_With_Guid_Equals_String() { diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Person.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Person.cs index 13f29edc..2a8c8f82 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Person.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Person.cs @@ -4,7 +4,13 @@ namespace System.Linq.Dynamic.Core.Tests.Helpers.Models public class Person { public int Id { get; set; } + public int? NullableId { get; set; } + public string Name { get; set; } + + public DateTime D { get; set; } + + public DateTimeOffset O { get; set; } } -} +} \ No newline at end of file From f767c22b4cf9aad01afb5a6c398bf8a46dac9008 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Thu, 17 Nov 2022 19:47:13 +0100 Subject: [PATCH 016/214] DynamicExpressionParser_ParseLambda_Func2 #648 --- .../DynamicExpressionParserTests.cs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 342182a6..dc3724cb 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -1482,7 +1482,15 @@ public void DynamicExpressionParser_ParseLambda_Action() public void DynamicExpressionParser_ParseLambda_Func() { // Arrange - var func = (Func)DynamicExpressionParser.ParseLambda(typeof(Func), new[] { Expression.Parameter(typeof(int), "x") }, typeof(int), "x + 1").Compile(); + var func = (Func)DynamicExpressionParser.ParseLambda( + typeof(Func), + new[] + { + Expression.Parameter(typeof(int), "x") + }, + typeof(int), + "x + 1" + ).Compile(); // Act var result = func(4); @@ -1490,5 +1498,32 @@ public void DynamicExpressionParser_ParseLambda_Func() // Assert result.Should().Be(5); } + + [Theory] + [InlineData(1, true)] + [InlineData(5, false)] + public void DynamicExpressionParser_ParseLambda_Func2(int? input, bool expected) + { + // Arrange + var nullableType = typeof(int?); + var functionType = typeof(Func<,>).MakeGenericType(nullableType, typeof(bool)); + var valueParameter = Expression.Parameter(nullableType, "value"); + + // Act 1 + var expression = DynamicExpressionParser.ParseLambda( + functionType, + new ParsingConfig(), + new[] { valueParameter }, + typeof(bool), + "value != null && value == 1" + ); + + // Act 2 + var compiledExpression = expression.Compile(); + var result = compiledExpression.DynamicInvoke(input); + + // Assert + result.Should().Be(expected); + } } } \ No newline at end of file From ec55d3473504ed80fe64ba6318253fe802216280 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 18 Nov 2022 19:52:37 +0100 Subject: [PATCH 017/214] update readme add net7.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 164a856f..694dae06 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ db.Customers.WhereInterpolated($"City == {cityName} and Orders.Count >= {c}"); The following frameworks are supported: - net35, net40, net45, net46 and up - netstandard1.3, netstandard2.0 and netstandard2.1 -- netcoreapp3.1, net5.0 and net6.0 +- netcoreapp3.1, net5.0, net6.0 and net7.0 - uap10.0 ### Fork details From c035e5b3ef9b7fc66c34b5b3102bb0649e089f34 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 26 Nov 2022 10:16:43 +0100 Subject: [PATCH 018/214] Support nullable notation "xxx?" in As expression (#647) * Support nullable notation "xxx?" in As expression * int? * ut * . * ut * ExpressionTests_Cast_To_Enum + ExpressionTests_Cast_To_NullableEnum * - * more tests --- .../ConsoleApp_net6.0.csproj | 17 ++-- src-console/ConsoleApp_net6.0/Program.cs | 26 ++++- .../DefaultDynamicLinqCustomTypeProvider.cs | 4 +- .../Extensions/LinqExtensions.cs | 13 +++ .../Parser/ExpressionParser.cs | 9 +- .../Parser/TypeHelper.cs | 19 +++- ...System.Linq.Dynamic.Core.Tests.Net7.csproj | 2 +- .../Entities/Department.cs | 2 + .../ExpressionTests.cs | 95 ++++++++++++++++++- .../Helpers/Models/SimpleValuesModel.cs | 22 ++++- .../QueryableTests.Is,OfType,As,Cast.cs | 68 +++++++++++++ 11 files changed, 253 insertions(+), 24 deletions(-) create mode 100644 src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs diff --git a/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj b/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj index 9e2ed750..84ca9532 100644 --- a/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj +++ b/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj @@ -1,13 +1,14 @@ - - Exe - net6.0 - ConsoleApp_net6._0 - + + Exe + net6.0 + ConsoleApp_net6._0 + enable + - - - + + + diff --git a/src-console/ConsoleApp_net6.0/Program.cs b/src-console/ConsoleApp_net6.0/Program.cs index b9c1afe7..b471cac2 100644 --- a/src-console/ConsoleApp_net6.0/Program.cs +++ b/src-console/ConsoleApp_net6.0/Program.cs @@ -1,17 +1,35 @@ -using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; namespace ConsoleApp_net6._0 { + public class X + { + public string Key { get; set; } = null!; + + public List? Contestants { get; set; } + } + + public class Y + { + } + class Program { static void Main(string[] args) { + var q = new[] + { + new X { Key = "x" }, + new X { Key = "a" }, + new X { Key = "a", Contestants = new List { new Y() } } + }.AsQueryable(); + var groupByKey = q.GroupBy("Key"); + var selectQry = groupByKey.Select("new (Key, Sum(np(Contestants.Count, 0)) As TotalCount)").ToDynamicList(); + Normal(); Dynamic(); - - int y = 0; } private static void Normal() @@ -40,4 +58,4 @@ private static void Dynamic() //var d = q.FirstOrDefault(i => i == 0, 42); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs index e6fc9430..421ec713 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs @@ -66,7 +66,7 @@ public Dictionary> GetExtensionMethods() /// public Type? ResolveType(string typeName) { - Check.NotEmpty(typeName, nameof(typeName)); + Check.NotEmpty(typeName); IEnumerable assemblies = _assemblyHelper.GetAssemblies(); return ResolveType(assemblies, typeName); @@ -75,7 +75,7 @@ public Dictionary> GetExtensionMethods() /// public Type? ResolveTypeBySimpleName(string simpleTypeName) { - Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); + Check.NotEmpty(simpleTypeName); IEnumerable assemblies = _assemblyHelper.GetAssemblies(); return ResolveTypeBySimpleName(assemblies, simpleTypeName); diff --git a/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs b/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs new file mode 100644 index 00000000..a0c0a5f3 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace System.Linq.Dynamic.Core.Extensions +{ + internal static class LinqExtensions + { + // Ex: collection.TakeLast(5); + public static IEnumerable TakeLast(this IList source, int n) + { + return source.Skip(Math.Max(0, source.Count() - n)); + } + } +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index ace1822f..7feddedc 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1907,13 +1907,20 @@ private Type ResolveTypeFromArgumentExpression(string functionName, Expression a private Type ResolveTypeStringFromArgument(string typeName) { + bool typeIsNullable = false; + if (typeName.EndsWith("?")) + { + typeName = typeName.TrimEnd('?'); + typeIsNullable = true; + } + var resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); if (resultType == null) { throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, typeName); } - return resultType; + return typeIsNullable ? TypeHelper.ToNullableType(resultType) : resultType; } private Expression[] ParseArgumentList() diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index bdf56d72..6e466224 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -311,16 +311,29 @@ public static bool IsNullableType(Type type) public static bool TypeCanBeNull(Type type) { - Check.NotNull(type, nameof(type)); + Check.NotNull(type); return !type.GetTypeInfo().IsValueType || IsNullableType(type); } public static Type ToNullableType(Type type) { - Check.NotNull(type, nameof(type)); + Check.NotNull(type); + + if (IsNullableType(type)) + { + // Already nullable, just return the type. + return type; + } + + if (!type.GetTypeInfo().IsValueType) + { + // Type is a not a value type, just return the type. + return type; + } - return IsNullableType(type) ? type : typeof(Nullable<>).MakeGenericType(type); + // Convert type to a nullable type + return typeof(Nullable<>).MakeGenericType(type); } public static bool IsSignedIntegralType(Type type) diff --git a/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj b/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj index 90dcec95..1661a129 100644 --- a/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj +++ b/test/System.Linq.Dynamic.Core.Tests.Net7/System.Linq.Dynamic.Core.Tests.Net7.csproj @@ -7,7 +7,7 @@ True ../../src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.snk false - + enable $(DefineConstants);NETCOREAPP;EFCORE;EFCORE_3X;NETCOREAPP3_1 diff --git a/test/System.Linq.Dynamic.Core.Tests/Entities/Department.cs b/test/System.Linq.Dynamic.Core.Tests/Entities/Department.cs index 2131ce39..ec0c817f 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Entities/Department.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Entities/Department.cs @@ -3,5 +3,7 @@ public class Department { public BaseEmployee Employee { get; set; } + + public BaseEmployee? NullableEmployee { get; set; } } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index d56c829e..aa845375 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; using System.Dynamic; using System.Globalization; +using System.Linq.Dynamic.Core.CustomTypeProviders; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Tests.Helpers; using System.Linq.Dynamic.Core.Tests.Helpers.Models; using FluentAssertions; +using Moq; using Newtonsoft.Json.Linq; using NFluent; using Xunit; @@ -251,7 +253,7 @@ public void ExpressionTests_BinaryOrNumericConvert() } [Fact] - public void ExpressionTests_Cast_To_nullableint() + public void ExpressionTests_Cast_To_NullableInt() { // Arrange var list = new List @@ -268,7 +270,94 @@ public void ExpressionTests_Cast_To_nullableint() } [Fact] - public void ExpressionTests_Cast_Automatic_To_nullablelong() + public void ExpressionTests_Cast_To_Enum_Using_DynamicLinqType() + { + // Arrange + var list = new List + { + new SimpleValuesModel { EnumValueDynamicLinqType = SimpleValuesModelEnumAsDynamicLinqType.A } + }; + + // Act + var expectedResult = list.Select(x => x.EnumValueDynamicLinqType); + var result = list.AsQueryable().Select("SimpleValuesModelEnumAsDynamicLinqType(EnumValueDynamicLinqType)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_To_Enum_Using_CustomTypeProvider() + { + // Arrange + var dynamicLinqCustomTypeProviderMock = new Mock(); + dynamicLinqCustomTypeProviderMock.Setup(d => d.GetCustomTypes()).Returns(new HashSet { typeof(SimpleValuesModelEnum) }); + var config = new ParsingConfig + { + CustomTypeProvider = dynamicLinqCustomTypeProviderMock.Object + }; + + var list = new List + { + new SimpleValuesModel { EnumValue = SimpleValuesModelEnum.A } + }; + + // Act + var expectedResult = list.Select(x => x.EnumValue); + var result = list.AsQueryable().Select(config, "SimpleValuesModelEnum(EnumValue)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_To_NullableEnum_Using_DynamicLinqType() + { + // Arrange + var list = new List + { + new SimpleValuesModel { EnumValueDynamicLinqType = SimpleValuesModelEnumAsDynamicLinqType.A } + }; + + // Act + var expectedResult = list.Select(x => (SimpleValuesModelEnumAsDynamicLinqType?)x.EnumValueDynamicLinqType); + var result = list.AsQueryable().Select("SimpleValuesModelEnumAsDynamicLinqType?(EnumValueDynamicLinqType)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_To_NullableEnum_Using_CustomTypeProvider() + { + // Arrange + var dynamicLinqCustomTypeProviderMock = new Mock(); + dynamicLinqCustomTypeProviderMock.Setup(d => d.GetCustomTypes()).Returns(new HashSet + { + typeof(SimpleValuesModelEnum), + typeof(SimpleValuesModelEnum?) + }); + + var config = new ParsingConfig + { + CustomTypeProvider = dynamicLinqCustomTypeProviderMock.Object + }; + + var list = new List + { + new SimpleValuesModel { EnumValue = SimpleValuesModelEnum.A } + }; + + // Act + var expectedResult = list.Select(x => (SimpleValuesModelEnum?)x.EnumValue); + var result = list.AsQueryable().Select(config, $"SimpleValuesModelEnum?(EnumValue)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_Automatic_To_NullableLong() { // Arrange var q = new[] { null, new UserProfile(), new UserProfile { UserProfileDetails = new UserProfileDetails { Id = 42 } } }.AsQueryable(); @@ -282,7 +371,7 @@ public void ExpressionTests_Cast_Automatic_To_nullablelong() } [Fact] - public void ExpressionTests_Cast_To_newnullableint() + public void ExpressionTests_Cast_To_NewNullableInt() { // Arrange var list = new List diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs index aad72b45..c431f380 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs @@ -1,6 +1,20 @@ - +using System.Linq.Dynamic.Core.CustomTypeProviders; + namespace System.Linq.Dynamic.Core.Tests.Helpers.Models { + public enum SimpleValuesModelEnum + { + A, + B + } + + [DynamicLinqType] + public enum SimpleValuesModelEnumAsDynamicLinqType + { + A, + B + } + public class SimpleValuesModel { public int IntValue { get; set; } @@ -14,5 +28,9 @@ public class SimpleValuesModel public int? NullableIntValue { get; set; } public double? NullableDoubleValue { get; set; } + + public SimpleValuesModelEnum EnumValue { get; set; } + + public SimpleValuesModelEnumAsDynamicLinqType EnumValueDynamicLinqType { get; set; } } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Is,OfType,As,Cast.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Is,OfType,As,Cast.cs index 7923c549..dfae87c9 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Is,OfType,As,Cast.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Is,OfType,As,Cast.cs @@ -200,6 +200,74 @@ public void As_Dynamic_ActingOnProperty() countAsDynamic.Should().Be(1); } + [Fact] + public void As_Dynamic_ActingOnProperty_NullableInt() + { + // Assign + var qry = new[] + { + new { Value = (int?) null }, + new { Value = (int?) 2 }, + new { Value = (int?) 42 } + + }.AsQueryable(); + + // Act + int count = qry.Count(x => x.Value as int? != null); + int? countAsDynamic = qry.Count("As(Value, \"int?\") != null"); + + // Assert + countAsDynamic.Should().Be(count); + } + + public enum TestEnum + { + None = 0, + + X = 1 + } + + [Fact] + public void As_Dynamic_ActingOnProperty_NullableEnum() + { + // Assign + var nullableEnumType = $"{typeof(TestEnum).FullName}?"; + var qry = new[] + { + new { Value = TestEnum.X } + }.AsQueryable(); + + // Act + int countAsDynamic = qry.Count($"As(Value, \"{nullableEnumType}\") != null"); + + // Assert + countAsDynamic.Should().Be(1); + } + + [Fact] + public void As_Dynamic_ActingOnProperty_NullableClass() + { + // Assign + var nullableClassType = $"{typeof(Worker).FullName}?"; + var qry = new[] + { + new Department + { + NullableEmployee = new Worker { Name = "1" } + }, + new Department + { + NullableEmployee = new Boss { Name = "b" } + } + }.AsQueryable(); + + // Act + int countAsDynamic = qry.Count($"As(NullableEmployee, \"{nullableClassType}\") != null"); + + // Assert + countAsDynamic.Should().Be(1); + } + [Fact] public void As_Dynamic_ActingOnProperty_WithType() { From a92a5ee6f1db1f9d5cca6d8a24c1377381c88532 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 26 Nov 2022 10:16:58 +0100 Subject: [PATCH 019/214] Fix Join on inherited class (#621) * Fix Join on inherited class * . * 02 --- .../DynamicQueryableExtensions.cs | 47 ++++++---- .../Parser/TypeHelper.cs | 10 ++- .../TypeConverters/ITypeConverterFactory.cs | 2 +- ...yFramework.DynamicLinq.Tests.net452.csproj | 3 + .../EntityFramework.DynamicLinq.Tests.csproj | 1 - .../Helpers/Models/Pet.cs | 2 +- .../Helpers/Models/SpecialPet.cs | 8 ++ .../QueryableTests.Join.cs | 87 ++++++++++++------- 8 files changed, 106 insertions(+), 54 deletions(-) create mode 100644 test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SpecialPet.cs diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index fb57326b..8908434d 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -2690,29 +2690,42 @@ private static bool SupportsLinqToObjects(ParsingConfig config, IQueryable query private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object?[] args) { - Type outerSelectorReturnType = outerSelectorLambda.Body.Type; - Type innerSelectorReturnType = innerSelectorLambda.Body.Type; + var outerSelectorReturnTypes = TypeHelper.GetSelfAndBaseTypes(outerSelectorLambda.Body.Type, true); + var innerSelectorReturnTypes = TypeHelper.GetSelfAndBaseTypes(innerSelectorLambda.Body.Type, true); - // If types are not the same, try to convert to Nullable and generate new LambdaExpression - if (outerSelectorReturnType != innerSelectorReturnType) + foreach (var outerSelectorReturnTypeInLoop in outerSelectorReturnTypes) { - if (TypeHelper.IsNullableType(outerSelectorReturnType) && !TypeHelper.IsNullableType(innerSelectorReturnType)) - { - innerSelectorReturnType = ExpressionParser.ToNullableType(innerSelectorReturnType); - innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, innerSelectorReturnType, innerKeySelector, args); - } - else if (!TypeHelper.IsNullableType(outerSelectorReturnType) && TypeHelper.IsNullableType(innerSelectorReturnType)) - { - outerSelectorReturnType = ExpressionParser.ToNullableType(outerSelectorReturnType); - outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, outerSelectorReturnType, outerKeySelector, args); - } + var outerSelectorBodyType = outerSelectorReturnTypeInLoop; - // If types are still not the same, throw an Exception - if (outerSelectorReturnType != innerSelectorReturnType) + foreach (var innerSelectorReturnTypeInLoop in innerSelectorReturnTypes) { - throw new ParseException(string.Format(CultureInfo.CurrentCulture, Res.IncompatibleTypes, outerSelectorReturnType, innerSelectorReturnType), -1); + var innerSelectorBodyType = innerSelectorReturnTypeInLoop; + + // If types are not the same, try to convert to Nullable and generate new LambdaExpression + if (outerSelectorBodyType != innerSelectorBodyType) + { + if (TypeHelper.IsNullableType(outerSelectorReturnTypeInLoop) && !TypeHelper.IsNullableType(innerSelectorReturnTypeInLoop)) + { + innerSelectorBodyType = ExpressionParser.ToNullableType(innerSelectorReturnTypeInLoop); + innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, innerSelectorBodyType, innerKeySelector, args); + } + else if (!TypeHelper.IsNullableType(outerSelectorReturnTypeInLoop) && TypeHelper.IsNullableType(innerSelectorReturnTypeInLoop)) + { + outerSelectorBodyType = ExpressionParser.ToNullableType(outerSelectorReturnTypeInLoop); + outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, outerSelectorBodyType, outerKeySelector, args); + } + } + + if (outerSelectorBodyType == innerSelectorBodyType) + { + // Types are equal (maybe after converting to nullable or after lopping), return from method. + return; + } } } + + // If types are still not the same, throw an Exception + throw new ParseException(string.Format(CultureInfo.CurrentCulture, Res.IncompatibleTypes, outerSelectorLambda.Body.Type, innerSelectorLambda.Body.Type), -1); } // Code below is based on https://github.com/aspnet/EntityFramework/blob/9186d0b78a3176587eeb0f557c331f635760fe92/src/Microsoft.EntityFrameworkCore/EntityFrameworkQueryableExtensions.cs diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index 6e466224..c648bc1f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -432,15 +432,18 @@ public static Type GetUnderlyingType(Type type) return type; } - public static IEnumerable GetSelfAndBaseTypes(Type type) + public static IList GetSelfAndBaseTypes(Type type, bool excludeObject = false) { + Check.NotNull(type, nameof(type)); + if (type.GetTypeInfo().IsInterface) { var types = new List(); AddInterface(types, type); return types; } - return GetSelfAndBaseClasses(type); + + return GetSelfAndBaseClasses(type).Where(t => !excludeObject || t != typeof(object)).ToList(); } private static IEnumerable GetSelfAndBaseClasses(Type type) @@ -452,11 +455,12 @@ private static IEnumerable GetSelfAndBaseClasses(Type type) } } - private static void AddInterface(List types, Type type) + private static void AddInterface(ICollection types, Type type) { if (!types.Contains(type)) { types.Add(type); + foreach (Type t in type.GetInterfaces()) { AddInterface(types, t); diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs index ad947160..0c33f6ce 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs @@ -2,7 +2,7 @@ namespace System.Linq.Dynamic.Core.TypeConverters; -interface ITypeConverterFactory +internal interface ITypeConverterFactory { /// /// Returns a type converter for the specified type. diff --git a/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj b/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj index 3c1b2052..1a902f66 100644 --- a/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj +++ b/test/EntityFramework.DynamicLinq.Tests.net452/EntityFramework.DynamicLinq.Tests.net452.csproj @@ -264,6 +264,9 @@ Helpers\Models\SimpleValuesModel.cs + + Helpers\Models\SpecialPet.cs + Helpers\Models\User.cs diff --git a/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj b/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj index 2b92aadc..f3a1caeb 100644 --- a/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj +++ b/test/EntityFramework.DynamicLinq.Tests/EntityFramework.DynamicLinq.Tests.csproj @@ -24,7 +24,6 @@ - diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Pet.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Pet.cs index bbfae274..a3b84874 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Pet.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/Pet.cs @@ -9,4 +9,4 @@ public class Pet public int OwnerId { get; set; } public int? NullableOwnerId { get; set; } } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SpecialPet.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SpecialPet.cs new file mode 100644 index 00000000..cce33896 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SpecialPet.cs @@ -0,0 +1,8 @@ + +namespace System.Linq.Dynamic.Core.Tests.Helpers.Models +{ + public class SpecialPet : Pet + { + public bool IsSpecial { get; set; } + } +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Join.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Join.cs index 0bd14946..e2ad10f5 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Join.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Join.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Tests.Helpers.Models; +using FluentAssertions; using NFluent; using Xunit; @@ -9,58 +10,82 @@ namespace System.Linq.Dynamic.Core.Tests public partial class QueryableTests { [Fact] - public void Join() + public void Join_InheritedClasses() { - //Arrange - Person magnus = new Person { Name = "Hedlund, Magnus" }; - Person terry = new Person { Name = "Adams, Terry" }; - Person charlotte = new Person { Name = "Weiss, Charlotte" }; + // Arrange + var magnus = new Person { Name = "Hedlund, Magnus" }; + var terry = new Person { Name = "Adams, Terry" }; + var charlotte = new Person { Name = "Weiss, Charlotte" }; - Pet barley = new Pet { Name = "Barley", Owner = terry }; - Pet boots = new Pet { Name = "Boots", Owner = terry }; - Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; - Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + var barley = new Pet { Name = "Barley", Owner = terry }; + var boots = new Pet { Name = "Boots", Owner = terry }; + var whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + var daisy = new SpecialPet { Name = "Daisy", Owner = magnus, IsSpecial = true }; var people = new List { magnus, terry, charlotte }; var pets = new List { barley, boots, whiskers, daisy }; - //Act + // Act 1 var realQuery = people.AsQueryable() .Join( pets, person => person, pet => pet.Owner, - (person, pet) => new { OwnerName = person.Name, Pet = pet.Name }); + (person, pet) => new { OwnerName = person.Name, Pet = pet.Name } + ); + var realResult = realQuery.ToList(); + // Act 2 var dynamicQuery = people.AsQueryable() .Join( pets, "it", "Owner", - "new(outer.Name as OwnerName, inner.Name as Pet)"); + "new(outer.Name as OwnerName, inner.Name as Pet)" + ); + var dynamicResult = dynamicQuery.ToDynamicList(); - //Assert - var realResult = realQuery.ToArray(); + // Assert + realResult.Should().BeEquivalentTo(dynamicResult); + } -#if NETSTANDARD - var dynamicResult = dynamicQuery.ToDynamicArray(); + [Fact] + public void Join() + { + // Arrange + var magnus = new Person { Name = "Hedlund, Magnus" }; + var terry = new Person { Name = "Adams, Terry" }; + var charlotte = new Person { Name = "Weiss, Charlotte" }; - Assert.Equal(realResult.Length, dynamicResult.Length); - for (int i = 0; i < realResult.Length; i++) - { - Assert.Equal(realResult[i].OwnerName, dynamicResult[i].GetDynamicPropertyValue("OwnerName")); - Assert.Equal(realResult[i].Pet, dynamicResult[i].GetDynamicPropertyValue("Pet")); - } -#else - var dynamicResult = dynamicQuery.ToDynamicArray(); + var barley = new Pet { Name = "Barley", Owner = terry }; + var boots = new Pet { Name = "Boots", Owner = terry }; + var whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + var daisy = new Pet { Name = "Daisy", Owner = magnus }; - Assert.Equal(realResult.Length, dynamicResult.Length); - for (int i = 0; i < realResult.Length; i++) - { - Assert.Equal(realResult[i].OwnerName, ((dynamic) dynamicResult[i]).OwnerName); - Assert.Equal(realResult[i].Pet, ((dynamic) dynamicResult[i]).Pet); - } -#endif + var people = new List { magnus, terry, charlotte }; + var pets = new List { barley, boots, whiskers, daisy }; + + // Act 1 + var realQuery = people.AsQueryable() + .Join( + pets, + person => person, + pet => pet.Owner, + (person, pet) => new { OwnerName = person.Name, Pet = pet.Name } + ); + var realResult = realQuery.ToList(); + + // Act 2 + var dynamicQuery = people.AsQueryable() + .Join( + pets, + "it", + "Owner", + "new(outer.Name as OwnerName, inner.Name as Pet)"); + var dynamicResult = dynamicQuery.ToDynamicList(); + + // Assert + realResult.Should().BeEquivalentTo(dynamicResult); } [Fact] From 3e377cfdb24b02991b5b8f3532ea64f268fcbc1a Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 27 Nov 2022 15:10:03 +0100 Subject: [PATCH 020/214] CI Workflow CI Workflow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 694dae06..c54e1ec2 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ db.Customers.WhereInterpolated($"City == {cityName} and Orders.Count >= {c}"); |   **Issues** | [![GitHub issues](https://img.shields.io/github/issues/StefH/System.Linq.Dynamic.Core.svg)](https://github.com/StefH/System.Linq.Dynamic.Core/issues) | | | | | ***Quality*** |   | -|   **Main workflow** | ![Main workflow](https://github.com/zzzprojects/System.Linq.Dynamic.Core/workflows/Main%20workflow/badge.svg) | +|   **CI Workflow** | ![CI Workflow](https://github.com/zzzprojects/System.Linq.Dynamic.Core/actions/workflows/ci.yml/badge.svg) | | | | ***NuGet*** |   | |   **System.Linq.Dynamic.Core** | [![NuGet](https://buildstats.info/nuget/System.Linq.Dynamic.Core)](https://www.nuget.org/packages/System.Linq.Dynamic.Core) | From 7729996d62008c4723f60cf5e72fce782a35c981 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 29 Nov 2022 11:49:31 +0100 Subject: [PATCH 021/214] Add support to cast to a fully qualified type (#653) * ... * fix * x * 24-preview-01 * 24-preview-02 --- CHANGELOG.md | 6 + Generate-ReleaseNotes.bat | 2 +- src-console/ConsoleAppEF6_InMemory/Program.cs | 14 +- .../AnyOfTypes/AnyOfTypes.g.cs | 16 ++ .../AnyOfTypes/AnyOf_2.g.cs | 156 ++++++++++++++++++ .../AnyOfTypes/HashCodeCalculator.g.cs | 30 ++++ .../Parser/ExpressionParser.cs | 53 ++++-- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 32 ++-- .../DynamicExpressionParserTests.cs | 6 +- .../ExpressionTests.cs | 68 ++++++++ .../Helpers/Models/SimpleValuesModel.cs | 2 + version.xml | 2 +- 12 files changed, 359 insertions(+), 28 deletions(-) create mode 100644 src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOfTypes.g.cs create mode 100644 src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOf_2.g.cs create mode 100644 src/System.Linq.Dynamic.Core/AnyOfTypes/HashCodeCalculator.g.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d177df0..143ce55e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.2.24 (27 November 2022) +- [#621](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/621) - Fix Join on inherited class [bug] contributed by [StefH](https://github.com/StefH) +- [#646](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/646) - Add more unittests for issue 645 contributed by [StefH](https://github.com/StefH) +- [#647](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/647) - Support nullable notation "xxx?" in As expression [feature] contributed by [StefH](https://github.com/StefH) +- [#614](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/614) - Join problem with inherited entities [bug] + # v1.2.23 (12 November 2022) - [#644](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/644) - Add support for .NET 7 and EF Core 7 [feature] contributed by [StefH](https://github.com/StefH) diff --git a/Generate-ReleaseNotes.bat b/Generate-ReleaseNotes.bat index 4d61cd78..a4e98cd5 100644 --- a/Generate-ReleaseNotes.bat +++ b/Generate-ReleaseNotes.bat @@ -1,5 +1,5 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=v1.2.23 +SET version=v1.2.24 GitHubReleaseNotes --output CHANGELOG.md --exclude-labels invalid question documentation wontfix --language en --version %version% --token %GH_TOKEN% diff --git a/src-console/ConsoleAppEF6_InMemory/Program.cs b/src-console/ConsoleAppEF6_InMemory/Program.cs index c223bc1a..a924708f 100644 --- a/src-console/ConsoleAppEF6_InMemory/Program.cs +++ b/src-console/ConsoleAppEF6_InMemory/Program.cs @@ -18,13 +18,25 @@ static async Task Main(string[] args) await using (var context = new TestContextEF6()) { context.Products.Add(new ProductDynamic { NullableInt = 1, Dict = new Dictionary { { "Name", "test" } } }); + context.Products.Add(new ProductDynamic { NullableInt = 2, Dict = new Dictionary { { "Name1", "test1" } } }); await context.SaveChangesAsync(); } + await using (var context = new TestContextEF6()) + { + var intType = typeof(int).FullName; + + var a1 = context.Products.Select($"\"{intType}\"(Key)").ToDynamicArray(); + Console.WriteLine("a1 {0}", string.Join(",", a1)); + + var a2 = context.Products.Select($"\"{intType}\"?(Key)").ToDynamicArray(); + Console.WriteLine("a2 {0}", string.Join(",", a2)); + } + await using (var context = new TestContextEF6()) { var resultsNormal = context.Products.Where(p => p.Dict["Name"] == "test").ToListAsync(); - + var results1 = await context.Products.Where("Dict.Name == @0", "test").ToListAsync(); Console.WriteLine("results1:"); foreach (var result in results1) diff --git a/src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOfTypes.g.cs b/src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOfTypes.g.cs new file mode 100644 index 00000000..840b4ddd --- /dev/null +++ b/src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOfTypes.g.cs @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by https://github.com/StefH/AnyOf. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace AnyOfTypes +{ + internal enum AnyOfType + { + Undefined = 0, First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth + } +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOf_2.g.cs b/src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOf_2.g.cs new file mode 100644 index 00000000..c2a62b99 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/AnyOfTypes/AnyOf_2.g.cs @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by https://github.com/StefH/AnyOf. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Collections.Generic; + +namespace AnyOfTypes +{ + [DebuggerDisplay("{_thisType}, AnyOfType = {_currentType}; Type = {_currentValueType?.Name}; Value = '{ToString()}'")] + internal struct AnyOf + { + private readonly string _thisType => $"AnyOf<{typeof(TFirst).Name}, {typeof(TSecond).Name}>"; + private readonly int _numberOfTypes; + private readonly object _currentValue; + private readonly Type _currentValueType; + private readonly AnyOfType _currentType; + + private readonly TFirst _first; + private readonly TSecond _second; + + public readonly AnyOfType[] AnyOfTypes => new[] { AnyOfType.First, AnyOfType.Second }; + public readonly Type[] Types => new[] { typeof(TFirst), typeof(TSecond) }; + public bool IsUndefined => _currentType == AnyOfType.Undefined; + public bool IsFirst => _currentType == AnyOfType.First; + public bool IsSecond => _currentType == AnyOfType.Second; + + public static implicit operator AnyOf(TFirst value) => new AnyOf(value); + + public static implicit operator TFirst(AnyOf @this) => @this.First; + + public AnyOf(TFirst value) + { + _numberOfTypes = 2; + _currentType = AnyOfType.First; + _currentValue = value; + _currentValueType = typeof(TFirst); + _first = value; + _second = default; + } + + public TFirst First + { + get + { + Validate(AnyOfType.First); + return _first; + } + } + + public static implicit operator AnyOf(TSecond value) => new AnyOf(value); + + public static implicit operator TSecond(AnyOf @this) => @this.Second; + + public AnyOf(TSecond value) + { + _numberOfTypes = 2; + _currentType = AnyOfType.Second; + _currentValue = value; + _currentValueType = typeof(TSecond); + _second = value; + _first = default; + } + + public TSecond Second + { + get + { + Validate(AnyOfType.Second); + return _second; + } + } + + private void Validate(AnyOfType desiredType) + { + if (desiredType != _currentType) + { + throw new InvalidOperationException($"Attempting to get {desiredType} when {_currentType} is set"); + } + } + + public AnyOfType CurrentType + { + get + { + return _currentType; + } + } + + public object CurrentValue + { + get + { + return _currentValue; + } + } + + public Type CurrentValueType + { + get + { + return _currentValueType; + } + } + + public override int GetHashCode() + { + var fields = new object[] + { + _numberOfTypes, + _currentValue, + _currentType, + _first, + _second, + typeof(TFirst), + typeof(TSecond), + }; + return HashCodeCalculator.GetHashCode(fields); + } + + private bool Equals(AnyOf other) + { + return _currentType == other._currentType && + _numberOfTypes == other._numberOfTypes && + EqualityComparer.Default.Equals(_currentValue, other._currentValue) && + EqualityComparer.Default.Equals(_first, other._first) && + EqualityComparer.Default.Equals(_second, other._second); + } + + public static bool operator ==(AnyOf obj1, AnyOf obj2) + { + return obj1.Equals(obj2); + } + + public static bool operator !=(AnyOf obj1, AnyOf obj2) + { + return !obj1.Equals(obj2); + } + + public override bool Equals(object obj) + { + return obj is AnyOf o && Equals(o); + } + + public override string ToString() + { + return IsUndefined ? null : $"{_currentValue}"; + } + } +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/AnyOfTypes/HashCodeCalculator.g.cs b/src/System.Linq.Dynamic.Core/AnyOfTypes/HashCodeCalculator.g.cs new file mode 100644 index 00000000..8305eaca --- /dev/null +++ b/src/System.Linq.Dynamic.Core/AnyOfTypes/HashCodeCalculator.g.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by https://github.com/StefH/AnyOf. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Linq; + +namespace AnyOfTypes +{ + // Code is based on https://github.com/Informatievlaanderen/hashcode-calculator + internal static class HashCodeCalculator + { + public static int GetHashCode(IEnumerable hashFieldValues) + { + const int offset = unchecked((int)2166136261); + const int prime = 16777619; + + static int HashCodeAggregator(int hashCode, object value) => value == null + ? (hashCode ^ 0) * prime + : (hashCode ^ value.GetHashCode()) * prime; + + return hashFieldValues.Aggregate(offset, HashCodeAggregator); + } + } +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 7feddedc..38f7a7fd 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -10,6 +10,7 @@ using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; using System.Reflection; +using AnyOfTypes; namespace System.Linq.Dynamic.Core.Parser { @@ -734,7 +735,7 @@ private Expression ParseUnary() private Expression ParsePrimary() { - Expression expr = ParsePrimaryStart(); + var expr = ParsePrimaryStart(); _expressionHelper.WrapConstantExpression(ref expr); while (true) @@ -757,6 +758,7 @@ private Expression ParsePrimary() break; } } + return expr; } @@ -766,38 +768,55 @@ private Expression ParsePrimaryStart() { case TokenId.Identifier: return ParseIdentifier(); + case TokenId.StringLiteral: - return ParseStringLiteral(); + var expressionOrType = ParseStringLiteral(false); + return expressionOrType.IsFirst ? expressionOrType.First : ParseTypeAccess(expressionOrType.Second, false); + case TokenId.IntegerLiteral: return ParseIntegerLiteral(); + case TokenId.RealLiteral: return ParseRealLiteral(); + case TokenId.OpenParen: return ParseParenExpression(); + default: throw ParseError(Res.ExpressionExpected); } } - private Expression ParseStringLiteral() + private AnyOf ParseStringLiteral(bool forceParseAsString) { _textParser.ValidateToken(TokenId.StringLiteral); - string result = StringParser.ParseString(_textParser.CurrentToken.Text); + var stringValue = StringParser.ParseString(_textParser.CurrentToken.Text); if (_textParser.CurrentToken.Text[0] == '\'') { - if (result.Length > 1) + if (stringValue.Length > 1) { throw ParseError(Res.InvalidCharacterLiteral); } _textParser.NextToken(); - return ConstantExpressionHelper.CreateLiteral(result[0], result); + return ConstantExpressionHelper.CreateLiteral(stringValue[0], stringValue); } _textParser.NextToken(); - return ConstantExpressionHelper.CreateLiteral(result, result); + + if (_parsingConfig.SupportFullTypeCastingUsingDoubleQuotes && !forceParseAsString && stringValue.Length > 2 && stringValue.Contains('.')) + { + // Try to resolve this string as a type + var type = _typeFinder.FindTypeByName(stringValue, null, false); + if (type is { }) + { + return type; + } + } + + return ConstantExpressionHelper.CreateLiteral(stringValue, stringValue); } private Expression ParseIntegerLiteral() @@ -844,7 +863,7 @@ private Expression ParseIdentifier() { if (value is Type typeValue) { - return ParseTypeAccess(typeValue); + return ParseTypeAccess(typeValue, true); } switch (value) @@ -1476,10 +1495,13 @@ private Expression ParseLambdaInvocation(LambdaExpression lambda) return Expression.Invoke(lambda, args); } - private Expression ParseTypeAccess(Type type) + private Expression ParseTypeAccess(Type type, bool getNext) { int errorPos = _textParser.CurrentToken.Pos; - _textParser.NextToken(); + if (getNext) + { + _textParser.NextToken(); + } if (_textParser.CurrentToken.Id == TokenId.Question) { @@ -1496,7 +1518,16 @@ private Expression ParseTypeAccess(Type type) bool shorthand = _textParser.CurrentToken.Id == TokenId.StringLiteral; if (_textParser.CurrentToken.Id == TokenId.OpenParen || shorthand) { - Expression[] args = shorthand ? new[] { ParseStringLiteral() } : ParseArgumentList(); + Expression[] args; + if (shorthand) + { + var expressionOrType = ParseStringLiteral(true); + args = new[] { expressionOrType.First }; + } + else + { + args = ParseArgumentList(); + } // If only 1 argument and // - the arg is ConstantExpression, return the conversion diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index da6c2a03..e7177079 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -107,7 +107,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// Determines if the context keywords (it, parent, and root) are valid and usable inside a Dynamic Linq string expression. /// Does not affect the usability of the equivalent context symbols ($, ^ and ~). /// - /// Default value is true. + /// Default value is false. /// public bool AreContextKeywordsEnabled { get; set; } = true; @@ -117,7 +117,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods. /// - /// Default value is false. + /// Default value is false. /// public bool EvaluateGroupByAtDatabase { get; set; } @@ -125,28 +125,28 @@ public IQueryableAnalyzer QueryableAnalyzer /// Use Parameterized Names in generated dynamic SQL query. /// See https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd /// - /// Default value is false. + /// Default value is false. /// public bool UseParameterizedNamesInDynamicQuery { get; set; } = false; /// /// Allows the New() keyword to evaluate any available Type. /// - /// Default value is false. + /// Default value is false. /// public bool AllowNewToEvaluateAnyType { get; set; } = false; /// /// Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from `it`. /// - /// Default value is false. + /// Default value is false. /// public bool RenameParameterExpression { get; set; } = false; /// /// Prevents any System.Linq.Expressions.ParameterExpression.Name value from being empty by substituting a random 16 character word. /// - /// Default value is false. + /// Default value is false. /// public bool RenameEmptyParameterExpressionNames { get; set; } @@ -155,7 +155,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// this flag to disable this behaviour and have parsing fail when parsing an expression /// where a member access on a non existing member happens. /// - /// Default value is false. + /// Default value is false. /// public bool DisableMemberAccessToIndexAccessorFallback { get; set; } = false; @@ -164,7 +164,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// Use this flag to use the CustomTypeProvider to resolve types by a simple name like "Employee" instead of "MyDatabase.Entities.Employee". /// Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution. /// - /// Default value is false. + /// Default value is false. /// public bool ResolveTypesBySimpleName { get; set; } = false; @@ -179,7 +179,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. /// Use this flag to parse all DateTime strings as UTC. /// - /// Default value is false. + /// Default value is false. /// public bool DateTimeIsParsedAsUTC { get; set; } = false; @@ -198,8 +198,18 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// When using the NullPropagating function np(...), use a "default value" for non-nullable value types instead of "null value". /// - /// Default value is false. + /// Default value is false. /// public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } = false; + + /// + /// Support casting to a full type using double quotes. + /// + /// var result = queryable.Select($"\"System.DateTime\"(LastUpdate)"); + /// + /// + /// Default value is true. + /// + public bool SupportFullTypeCastingUsingDoubleQuotes { get; set; } = true; } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index dc3724cb..68c79c64 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -384,15 +384,15 @@ public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQu var expressionAsString = expression.ToString(); // Assert - var queriedProp = typeof(SimpleValuesModel).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public); + var queriedProp = typeof(SimpleValuesModel).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public)!; var queriedPropType = queriedProp.PropertyType; var queriedPropUnderlyingType = Nullable.GetUnderlyingType(queriedPropType); Check.That(expressionAsString).IsEqualTo($"Param_0 => (Param_0.{propName} == {ExpressionString.NullableConversion($"value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[{queriedPropUnderlyingType}]).Value")})"); - dynamic constantExpression = ((MemberExpression)(((expression.Body as BinaryExpression).Right as UnaryExpression).Operand)).Expression as ConstantExpression; + dynamic constantExpression = (ConstantExpression)((MemberExpression)((UnaryExpression)((BinaryExpression)expression.Body).Right).Operand).Expression; object wrapperObj = constantExpression.Value; - var propertyInfo = wrapperObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); + var propertyInfo = wrapperObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public)!; var value = propertyInfo.GetValue(wrapperObj); value.Should().Be(Convert.ChangeType(valueString, Nullable.GetUnderlyingType(queriedPropType) ?? queriedPropType, culture)); diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index aa845375..f5537a6c 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -286,6 +286,74 @@ public void ExpressionTests_Cast_To_Enum_Using_DynamicLinqType() Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); } + [Fact] + public void ExpressionTests_Cast_To_FullTypeDateTime_Using_DynamicLinqType() + { + // Arrange + var list = new List + { + new SimpleValuesModel { DateTime = DateTime.Now } + }; + + // Act + var expectedResult = list.Select(x => x.DateTime); + var result = list.AsQueryable().Select($"\"{typeof(DateTime).FullName}\"(DateTime)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_To_FullTypeDateTimeNullable_Using_DynamicLinqType() + { + // Arrange + var list = new List + { + new SimpleValuesModel { DateTime = DateTime.Now } + }; + + // Act + var expectedResult = list.Select(x => (DateTime?)x.DateTime); + var result = list.AsQueryable().Select($"\"{typeof(DateTime).FullName}\"?(DateTime)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_To_FullTypeEnum_Using_DynamicLinqType() + { + // Arrange + var list = new List + { + new SimpleValuesModel { EnumValueDynamicLinqType = SimpleValuesModelEnumAsDynamicLinqType.A } + }; + + // Act + var expectedResult = list.Select(x => x.EnumValueDynamicLinqType); + var result = list.AsQueryable().Select($"\"{typeof(SimpleValuesModelEnumAsDynamicLinqType).FullName}\"(EnumValueDynamicLinqType)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + + [Fact] + public void ExpressionTests_Cast_To_FullTypeNullableEnum_Using_DynamicLinqType() + { + // Arrange + var list = new List + { + new SimpleValuesModel { EnumValueDynamicLinqType = SimpleValuesModelEnumAsDynamicLinqType.A } + }; + + // Act + var expectedResult = list.Select(x => (SimpleValuesModelEnumAsDynamicLinqType?)x.EnumValueDynamicLinqType); + var result = list.AsQueryable().Select($"\"{typeof(SimpleValuesModelEnumAsDynamicLinqType).FullName}\"?(EnumValueDynamicLinqType)"); + + // Assert + Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); + } + [Fact] public void ExpressionTests_Cast_To_Enum_Using_CustomTypeProvider() { diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs index c431f380..63a74d73 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/SimpleValuesModel.cs @@ -32,5 +32,7 @@ public class SimpleValuesModel public SimpleValuesModelEnum EnumValue { get; set; } public SimpleValuesModelEnumAsDynamicLinqType EnumValueDynamicLinqType { get; set; } + + public DateTime DateTime { get; set; } } } \ No newline at end of file diff --git a/version.xml b/version.xml index 165a71ac..1e9f7b0b 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 23 + 24-preview-02 From 7ac62daef9df21954aeacf175e2637c35993a049 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 30 Nov 2022 21:47:25 +0100 Subject: [PATCH 022/214] SupportCastingToFullyQualifiedTypeAsString --- src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs | 2 +- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 38f7a7fd..add203e1 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -806,7 +806,7 @@ private AnyOf ParseStringLiteral(bool forceParseAsString) _textParser.NextToken(); - if (_parsingConfig.SupportFullTypeCastingUsingDoubleQuotes && !forceParseAsString && stringValue.Length > 2 && stringValue.Contains('.')) + if (_parsingConfig.SupportCastingToFullyQualifiedTypeAsString && !forceParseAsString && stringValue.Length > 2 && stringValue.Contains('.')) { // Try to resolve this string as a type var type = _typeFinder.FindTypeByName(stringValue, null, false); diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index e7177079..aa4c1a6d 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -203,13 +203,13 @@ public IQueryableAnalyzer QueryableAnalyzer public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } = false; /// - /// Support casting to a full type using double quotes. + /// Support casting to a full qualified type using a string (double quoted value). /// /// var result = queryable.Select($"\"System.DateTime\"(LastUpdate)"); /// /// /// Default value is true. /// - public bool SupportFullTypeCastingUsingDoubleQuotes { get; set; } = true; + public bool SupportCastingToFullyQualifiedTypeAsString { get; set; } = true; } } \ No newline at end of file From 251d90e91e0e2c96cde0f769e239392c1a475190 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 4 Dec 2022 11:40:14 +0100 Subject: [PATCH 023/214] Fix DynamicExpressionParser and ExpressionPromoter to support LambdExpression (#649) * Fix DynamicExpressionParser and ExpressionPromoter to support LambdaExpression * ut --- .../DynamicExpressionParser.cs | 20 ++++++------ .../Parser/ExpressionPromoter.cs | 14 ++++++-- .../DynamicExpressionParserTests.cs | 32 ++++++++++++------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index c0629715..176158fd 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -120,24 +120,24 @@ public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? pa var parsedExpression = parser.Parse(resultType, createParameterCtor); - LambdaExpression lambdaExpression; + if (parsedExpression is LambdaExpression lambdaExpression) + { + return lambdaExpression; + } + if (parsingConfig is { RenameParameterExpression: true } && parameters.Length == 1) { var renamer = new ParameterExpressionRenamer(parser.LastLambdaItName); - parsedExpression = renamer.Rename(parsedExpression, out ParameterExpression newParameterExpression); + parsedExpression = renamer.Rename(parsedExpression, out var newParameterExpression); - lambdaExpression = delegateType == null ? + return delegateType == null ? Expression.Lambda(parsedExpression, newParameterExpression) : Expression.Lambda(delegateType, parsedExpression, newParameterExpression); } - else - { - lambdaExpression = delegateType == null ? - Expression.Lambda(parsedExpression, parameters) : - Expression.Lambda(delegateType, parsedExpression, parameters); - } - return lambdaExpression; + return delegateType == null ? + Expression.Lambda(parsedExpression, parameters) : + Expression.Lambda(delegateType, parsedExpression, parameters); } /// diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs index fea5eb2f..67df3632 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs @@ -22,7 +22,17 @@ public ExpressionPromoter(ParsingConfig config) /// public virtual Expression? Promote(Expression expr, Type type, bool exact, bool convertExpr) { - if (expr.Type == type || type.IsGenericParameter) + Type returnType; + if (expr is LambdaExpression lambdaExpression) + { + returnType = lambdaExpression.GetReturnType(); + } + else + { + returnType = expr.Type; + } + + if (returnType == type || type.IsGenericParameter) { return expr; } @@ -103,7 +113,7 @@ public ExpressionPromoter(ParsingConfig config) } } - if (TypeHelper.IsCompatibleWith(expr.Type, type)) + if (TypeHelper.IsCompatibleWith(returnType, type)) { if (type == typeof(decimal) && TypeHelper.IsEnumType(expr.Type)) { diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 68c79c64..297768d8 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -580,7 +580,7 @@ public void DynamicExpressionParser_ParseLambda_Select_2() // https://github.com/StefH/System.Linq.Dynamic.Core/issues/58 [Fact] - public void DynamicExpressionParser_ParseLambda_4_Issue58() + public void DynamicExpressionParser_ParseLambda_Issue58() { var expressionParams = new[] { @@ -1251,14 +1251,16 @@ public void DynamicExpressionParser_ParseLambda_Operator_Less_Greater_With_Guids } [Theory] - [InlineData("c => c.Age == 8", "c => (c.Age == 8)")] - [InlineData("c => c.Name == \"test\"", "c => (c.Name == \"test\")")] - public void DynamicExpressionParser_ParseLambda_RenameParameterExpression(string expressionAsString, string expected) + [InlineData(true, "c => c.Age == 8", "c => (c.Age == 8)")] + [InlineData(true, "c => c.Name == \"test\"", "c => (c.Name == \"test\")")] + [InlineData(false, "c => c.Age == 8", "Param_0 => (Param_0.Age == 8)")] + [InlineData(false, "c => c.Name == \"test\"", "Param_0 => (Param_0.Name == \"test\")")] + public void DynamicExpressionParser_ParseLambda_RenameParameterExpression(bool renameParameterExpression, string expressionAsString, string expected) { // Arrange var config = new ParsingConfig { - RenameParameterExpression = true + RenameParameterExpression = renameParameterExpression }; // Act @@ -1500,22 +1502,28 @@ public void DynamicExpressionParser_ParseLambda_Func() } [Theory] - [InlineData(1, true)] - [InlineData(5, false)] - public void DynamicExpressionParser_ParseLambda_Func2(int? input, bool expected) + [InlineData("value", "value != null && value == 1", 1, true)] + [InlineData("value", "value != null && value == 1", 5, false)] + [InlineData("x", "value != null && value == 1", 1, true)] + [InlineData("x", "value != null && value == 1", 5, false)] + [InlineData(null, "value != null && value == 1", 1, true)] + [InlineData(null, "value != null && value == 1", 5, false)] + [InlineData("value", "value => value != null && value == 1", 1, true)] + [InlineData("value", "value => value != null && value == 1", 5, false)] + public void DynamicExpressionParser_ParseLambda_Func2(string? paramName, string test, int? input, bool expected) { // Arrange var nullableType = typeof(int?); - var functionType = typeof(Func<,>).MakeGenericType(nullableType, typeof(bool)); - var valueParameter = Expression.Parameter(nullableType, "value"); + var delegateType = typeof(Func<,>).MakeGenericType(nullableType, typeof(bool)); + var valueParameter = paramName is not null ? Expression.Parameter(nullableType, paramName) : Expression.Parameter(nullableType); // Act 1 var expression = DynamicExpressionParser.ParseLambda( - functionType, + delegateType, new ParsingConfig(), new[] { valueParameter }, typeof(bool), - "value != null && value == 1" + test ); // Act 2 From a938e8cc6051fd885619fcec56bdab878109846e Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 4 Dec 2022 11:42:26 +0100 Subject: [PATCH 024/214] changelog --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 143ce55e..76ed6b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ -# v1.2.24 (27 November 2022) +# v1.2.24 (04 December 2022) - [#621](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/621) - Fix Join on inherited class [bug] contributed by [StefH](https://github.com/StefH) -- [#646](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/646) - Add more unittests for issue 645 contributed by [StefH](https://github.com/StefH) +- [#646](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/646) - Add more unittests for issue 645 [feature] contributed by [StefH](https://github.com/StefH) - [#647](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/647) - Support nullable notation "xxx?" in As expression [feature] contributed by [StefH](https://github.com/StefH) +- [#649](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/649) - Fix DynamicExpressionParser and ExpressionPromoter to support LambdExpression [bug] contributed by [StefH](https://github.com/StefH) +- [#653](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/653) - Add support to cast to a fully qualified type [feature] contributed by [StefH](https://github.com/StefH) - [#614](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/614) - Join problem with inherited entities [bug] +- [#652](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/652) - Implement casting to fully qualified type [feature] # v1.2.23 (12 November 2022) - [#644](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/644) - Add support for .NET 7 and EF Core 7 [feature] contributed by [StefH](https://github.com/StefH) From f4bfa99295d23fb32812055757aca8b0cd0efa30 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 18 Dec 2022 12:24:22 +0100 Subject: [PATCH 025/214] v1.2.24 --- CHANGELOG.md | 2 +- version.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76ed6b5e..6dbab80c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v1.2.24 (04 December 2022) +# v1.2.24 (18 December 2022) - [#621](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/621) - Fix Join on inherited class [bug] contributed by [StefH](https://github.com/StefH) - [#646](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/646) - Add more unittests for issue 645 [feature] contributed by [StefH](https://github.com/StefH) - [#647](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/647) - Support nullable notation "xxx?" in As expression [feature] contributed by [StefH](https://github.com/StefH) diff --git a/version.xml b/version.xml index 1e9f7b0b..56d94df6 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 24-preview-02 + 24 From f7b42edb06de35f1768c808dcdaf12d21ff15d7a Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 4 Feb 2023 11:16:05 +0100 Subject: [PATCH 026/214] Add config setting for PrioritizePropertyOrFieldOverTheType (#664) * ... * Add config setting for PrioritizePropertyOrFieldOverTheType --- .../Parser/ExpressionParser.cs | 22 +- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 9 + .../DynamicExpressionParserTests.cs | 6 +- .../Entities/Company.cs | 17 +- .../ExpressionTests.cs | 15 +- .../ExpressionParserTests.TypeAccess.cs | 15 + .../Parser/ExpressionParserTests.cs | 383 +++++++------ .../QueryableTests.GroupBy.cs | 2 +- .../QueryableTests.Select.cs | 1 - .../QueryableTests.Where.cs | 510 +++++++++--------- 10 files changed, 542 insertions(+), 438 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index add203e1..dad76ebd 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -857,9 +857,12 @@ private Expression ParseIdentifier() { _textParser.ValidateToken(TokenId.Identifier); - if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object? value) && - // Prioritize property or field over the type - !(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null)) + var isValidKeyWord = _keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out var value); + + var extraCondition = !_parsingConfig.PrioritizePropertyOrFieldOverTheType || + (_parsingConfig.PrioritizePropertyOrFieldOverTheType && !(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null)); + + if (isValidKeyWord && extraCondition) { if (value is Type typeValue) { @@ -1711,9 +1714,13 @@ private Expression ParseMemberAccess(Type? type, Expression? expression) return Expression.Field(expression, field); } - if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && expression != null) + // #357 #662 + var extraCheck = !_parsingConfig.PrioritizePropertyOrFieldOverTheType || + _parsingConfig.PrioritizePropertyOrFieldOverTheType && expression != null; + + if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && extraCheck) { - var indexerMethod = expression.Type.GetMethod("get_Item", new[] { typeof(string) }); + var indexerMethod = expression?.Type.GetMethod("get_Item", new[] { typeof(string) }); if (indexerMethod != null) { return Expression.Call(expression, indexerMethod, Expression.Constant(id)); @@ -2139,11 +2146,12 @@ private static Exception IncompatibleOperandsError(string opName, Expression lef private MemberInfo? FindPropertyOrField(Type type, string memberName, bool staticAccess) { #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) - BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); + var extraBindingFlag = _parsingConfig.PrioritizePropertyOrFieldOverTheType && staticAccess ? BindingFlags.Static : BindingFlags.Instance; + var bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly | extraBindingFlag; foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { var findMembersType = _parsingConfig?.IsCaseSensitive == true ? Type.FilterName : Type.FilterNameIgnoreCase; - var members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, flags, findMembersType, memberName); + var members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, bindingFlags, findMembersType, memberName); if (members.Length != 0) { diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index aa4c1a6d..66f41fab 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -211,5 +211,14 @@ public IQueryableAnalyzer QueryableAnalyzer /// Default value is true. /// public bool SupportCastingToFullyQualifiedTypeAsString { get; set; } = true; + + /// + /// When the type and property have the same name the parser takes the property instead of type when this setting is set to true. + /// + /// The value from this setting should also be set to true when ExtensionMethods are used. + /// + /// Default value is false. + /// + public bool PrioritizePropertyOrFieldOverTheType { get; set; } } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 297768d8..3bd1332c 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -1449,9 +1449,10 @@ public void DynamicExpressionParser_ParseLambda_GenericExtensionMethod() { // Arrange var testList = User.GenerateSampleModels(51); - var config = new ParsingConfig() + var config = new ParsingConfig { - CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod() + CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod(), + PrioritizePropertyOrFieldOverTheType = true }; // Act @@ -1461,7 +1462,6 @@ public void DynamicExpressionParser_ParseLambda_GenericExtensionMethod() var result = Enumerable.Where(testList, del); - var expected = testList.Where(x => new string[] { "User4", "User2" }.Contains(x.UserName)).ToList(); // Assert diff --git a/test/System.Linq.Dynamic.Core.Tests/Entities/Company.cs b/test/System.Linq.Dynamic.Core.Tests/Entities/Company.cs index a6a6e5c3..459dbca8 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Entities/Company.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Entities/Company.cs @@ -1,15 +1,16 @@ using System.Collections.Generic; -namespace System.Linq.Dynamic.Core.Tests.Entities +namespace System.Linq.Dynamic.Core.Tests.Entities; + +public class Company : Entity { - public class Company : Entity - { - public string Name { get; set; } + public string Name { get; set; } + + public long? MainCompanyId { get; set; } - public long? MainCompanyId { get; set; } + public MainCompany MainCompany { get; set; } - public MainCompany MainCompany { get; set; } + public ICollection Employees { get; set; } - public ICollection Employees { get; set; } - } + public DateTime DateTime { get; set; } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index f5537a6c..b9b8341a 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -290,6 +290,10 @@ public void ExpressionTests_Cast_To_Enum_Using_DynamicLinqType() public void ExpressionTests_Cast_To_FullTypeDateTime_Using_DynamicLinqType() { // Arrange + var config = new ParsingConfig + { + PrioritizePropertyOrFieldOverTheType = true + }; var list = new List { new SimpleValuesModel { DateTime = DateTime.Now } @@ -297,7 +301,7 @@ public void ExpressionTests_Cast_To_FullTypeDateTime_Using_DynamicLinqType() // Act var expectedResult = list.Select(x => x.DateTime); - var result = list.AsQueryable().Select($"\"{typeof(DateTime).FullName}\"(DateTime)"); + var result = list.AsQueryable().Select(config, $"\"{typeof(DateTime).FullName}\"(DateTime)"); // Assert Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); @@ -307,6 +311,10 @@ public void ExpressionTests_Cast_To_FullTypeDateTime_Using_DynamicLinqType() public void ExpressionTests_Cast_To_FullTypeDateTimeNullable_Using_DynamicLinqType() { // Arrange + var config = new ParsingConfig + { + PrioritizePropertyOrFieldOverTheType = true + }; var list = new List { new SimpleValuesModel { DateTime = DateTime.Now } @@ -314,7 +322,7 @@ public void ExpressionTests_Cast_To_FullTypeDateTimeNullable_Using_DynamicLinqTy // Act var expectedResult = list.Select(x => (DateTime?)x.DateTime); - var result = list.AsQueryable().Select($"\"{typeof(DateTime).FullName}\"?(DateTime)"); + var result = list.AsQueryable().Select(config, $"\"{typeof(DateTime).FullName}\"?(DateTime)"); // Assert Assert.Equal(expectedResult.ToArray(), result.ToDynamicArray()); @@ -1502,7 +1510,8 @@ public void ExpressionTests_MethodCall_GenericExtension() { var config = new ParsingConfig { - CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForStaticTesting() + CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForStaticTesting(), + PrioritizePropertyOrFieldOverTheType = true }; // Arrange diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs index c5bed90c..d79ca134 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs @@ -53,6 +53,21 @@ public void ParseTypeAccess_Via_Constructor_String_To_DateTime_Valid() expression.ToString().Should().NotBeEmpty(); } + [Fact] + public void ParseTypeAccess_Via_Constructor_Arguments_To_DateTime_Valid() + { + // Arrange + var arguments = "2022, 10, 31, 9, 15, 11"; + var parameter = Expression.Parameter(typeof(DateTime)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateTime({arguments})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateTime)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + [Theory] [InlineData(null)] [InlineData("\"abc\"")] diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs index 3015401a..b32c151c 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs @@ -1,224 +1,257 @@ -using FluentAssertions; -using Moq; -using NFluent; -using System.Collections.Generic; -using System.Globalization; +using System.Collections.Generic; using System.Linq.Dynamic.Core.CustomTypeProviders; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Parser; using System.Linq.Dynamic.Core.Tests.Entities; using System.Linq.Expressions; +using FluentAssertions; +using Moq; +using NFluent; using Xunit; -namespace System.Linq.Dynamic.Core.Tests.Parser +namespace System.Linq.Dynamic.Core.Tests.Parser; + +public partial class ExpressionParserTests { - public partial class ExpressionParserTests - { - private readonly ParsingConfig _parsingConfig; - private readonly Mock _dynamicTypeProviderMock; + private readonly Mock _dynamicTypeProviderMock; - public ExpressionParserTests() - { - _dynamicTypeProviderMock = new Mock(); - _dynamicTypeProviderMock.Setup(dt => dt.GetCustomTypes()).Returns(new HashSet() { typeof(Company), typeof(MainCompany) }); - _dynamicTypeProviderMock.Setup(dt => dt.ResolveType(typeof(Company).FullName)).Returns(typeof(Company)); - _dynamicTypeProviderMock.Setup(dt => dt.ResolveType(typeof(MainCompany).FullName)).Returns(typeof(MainCompany)); - _dynamicTypeProviderMock.Setup(dt => dt.ResolveTypeBySimpleName("Company")).Returns(typeof(Company)); - _dynamicTypeProviderMock.Setup(dt => dt.ResolveTypeBySimpleName("MainCompany")).Returns(typeof(MainCompany)); - - _parsingConfig = new ParsingConfig - { - CustomTypeProvider = _dynamicTypeProviderMock.Object - }; - } + private readonly ParsingConfig _parsingConfig; - [Fact] - public void Parse_ParseBinaryInteger() + public ExpressionParserTests() + { + _dynamicTypeProviderMock = new Mock(); + _dynamicTypeProviderMock.Setup(dt => dt.GetCustomTypes()).Returns(new HashSet() { typeof(Company), typeof(MainCompany) }); + _dynamicTypeProviderMock.Setup(dt => dt.ResolveType(typeof(Company).FullName!)).Returns(typeof(Company)); + _dynamicTypeProviderMock.Setup(dt => dt.ResolveType(typeof(MainCompany).FullName!)).Returns(typeof(MainCompany)); + _dynamicTypeProviderMock.Setup(dt => dt.ResolveTypeBySimpleName("Company")).Returns(typeof(Company)); + _dynamicTypeProviderMock.Setup(dt => dt.ResolveTypeBySimpleName("MainCompany")).Returns(typeof(MainCompany)); + + _parsingConfig = new ParsingConfig { - // Arrange - var expression = "0b1100000011101"; - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + CustomTypeProvider = _dynamicTypeProviderMock.Object + }; + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Fact] + public void Parse_ParseBinaryInteger() + { + // Arrange + var expression = "0b1100000011101"; + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Assert - parsedExpression.Should().Be("6173"); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Fact] - public void Parse_ParseHexadecimalInteger() - { - // Arrange - var expression = "0xFF"; - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + // Assert + parsedExpression.Should().Be("6173"); + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Fact] + public void Parse_ParseHexadecimalInteger() + { + // Arrange + var expression = "0xFF"; + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Assert - parsedExpression.Should().Be("255"); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Theory] - [InlineData("it == 1", "(x == 1)")] - [InlineData("it eq 1", "(x == 1)")] - [InlineData("it equal 1", "(x == 1)")] - [InlineData("it != 1", "(x != 1)")] - [InlineData("it ne 1", "(x != 1)")] - [InlineData("it neq 1", "(x != 1)")] - [InlineData("it notequal 1", "(x != 1)")] - [InlineData("it lt 1", "(x < 1)")] - [InlineData("it LessThan 1", "(x < 1)")] - [InlineData("it le 1", "(x <= 1)")] - [InlineData("it LessThanEqual 1", "(x <= 1)")] - [InlineData("it gt 1", "(x > 1)")] - [InlineData("it GreaterThan 1", "(x > 1)")] - [InlineData("it ge 1", "(x >= 1)")] - [InlineData("it GreaterThanEqual 1", "(x >= 1)")] - public void Parse_ParseComparisonOperator(string expression, string result) - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + // Assert + parsedExpression.Should().Be("255"); + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Theory] + [InlineData("it == 1", "(x == 1)")] + [InlineData("it eq 1", "(x == 1)")] + [InlineData("it equal 1", "(x == 1)")] + [InlineData("it != 1", "(x != 1)")] + [InlineData("it ne 1", "(x != 1)")] + [InlineData("it neq 1", "(x != 1)")] + [InlineData("it notequal 1", "(x != 1)")] + [InlineData("it lt 1", "(x < 1)")] + [InlineData("it LessThan 1", "(x < 1)")] + [InlineData("it le 1", "(x <= 1)")] + [InlineData("it LessThanEqual 1", "(x <= 1)")] + [InlineData("it gt 1", "(x > 1)")] + [InlineData("it GreaterThan 1", "(x > 1)")] + [InlineData("it ge 1", "(x >= 1)")] + [InlineData("it GreaterThanEqual 1", "(x >= 1)")] + public void Parse_ParseComparisonOperator(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Assert - Check.That(parsedExpression).Equals(result); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Theory] - [InlineData("it || true", "(x OrElse True)")] - [InlineData("it or true", "(x OrElse True)")] - [InlineData("it OrElse true", "(x OrElse True)")] - public void Parse_ParseOrOperator(string expression, string result) - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + // Assert + Check.That(parsedExpression).Equals(result); + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Theory] + [InlineData("it || true", "(x OrElse True)")] + [InlineData("it or true", "(x OrElse True)")] + [InlineData("it OrElse true", "(x OrElse True)")] + public void Parse_ParseOrOperator(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Assert - Check.That(parsedExpression).Equals(result); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Theory] - [InlineData("it && true", "(x AndAlso True)")] - [InlineData("it and true", "(x AndAlso True)")] - [InlineData("it AndAlso true", "(x AndAlso True)")] - public void Parse_ParseAndOperator(string expression, string result) - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + // Assert + Check.That(parsedExpression).Equals(result); + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Theory] + [InlineData("it && true", "(x AndAlso True)")] + [InlineData("it and true", "(x AndAlso True)")] + [InlineData("it AndAlso true", "(x AndAlso True)")] + public void Parse_ParseAndOperator(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Assert - Check.That(parsedExpression).Equals(result); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Fact] - public void Parse_ParseMultipleInOperators() - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "x") }; - var sut = new ExpressionParser(parameters, "MainCompanyId in (1, 2) and Name in (\"A\", \"B\")", null, null); + // Assert + Check.That(parsedExpression).Equals(result); + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Fact] + public void Parse_ParseMultipleInOperators() + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "x") }; + var sut = new ExpressionParser(parameters, "MainCompanyId in (1, 2) and Name in (\"A\", \"B\")", null, null); - // Assert - Check.That(parsedExpression).Equals("(((x.MainCompanyId == 1) OrElse (x.MainCompanyId == 2)) AndAlso ((x.Name == \"A\") OrElse (x.Name == \"B\")))"); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Fact] - public void Parse_ParseInWrappedInParenthesis() - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "x") }; - var sut = new ExpressionParser(parameters, "(MainCompanyId in @0)", new object[] { new long?[] { 1, 2 } }, null); + // Assert + Check.That(parsedExpression).Equals("(((x.MainCompanyId == 1) OrElse (x.MainCompanyId == 2)) AndAlso ((x.Name == \"A\") OrElse (x.Name == \"B\")))"); + } - // Act - var parsedExpression = sut.Parse(null).ToString(); + [Fact] + public void Parse_ParseInWrappedInParenthesis() + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "x") }; + var sut = new ExpressionParser(parameters, "(MainCompanyId in @0)", new object[] { new long?[] { 1, 2 } }, null); - // Assert - Check.That(parsedExpression).Equals("value(System.Nullable`1[System.Int64][]).Contains(x.MainCompanyId)"); - } + // Act + var parsedExpression = sut.Parse(null).ToString(); - [Theory] - [InlineData("string(\"\")", "")] - [InlineData("string(\"a\")", "a")] - [InlineData("int(42)", 42)] - public void Parse_CastStringIntShouldReturnConstantExpression(string expression, object result) - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + // Assert + Check.That(parsedExpression).Equals("value(System.Nullable`1[System.Int64][]).Contains(x.MainCompanyId)"); + } - // Act - var constantExpression = (ConstantExpression)sut.Parse(null); + [Theory] + [InlineData("string(\"\")", "")] + [InlineData("string(\"a\")", "a")] + [InlineData("int(42)", 42)] + public void Parse_CastStringIntShouldReturnConstantExpression(string expression, object result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Assert - Check.That(constantExpression.Value).Equals(result); - } + // Act + var constantExpression = (ConstantExpression)sut.Parse(null); + + // Assert + Check.That(constantExpression.Value).Equals(result); + } - [Theory] + [Theory] #if NET452 [InlineData("int?(5)", typeof(int?), "Convert(5)")] [InlineData("int?(null)", typeof(int?), "Convert(null)")] [InlineData("string(null)", typeof(string), "Convert(null)")] #else - [InlineData("int?(5)", typeof(int?), "Convert(5, Nullable`1)")] - [InlineData("int?(null)", typeof(int?), "Convert(null, Nullable`1)")] - [InlineData("string(null)", typeof(string), "Convert(null, String)")] + [InlineData("int?(5)", typeof(int?), "Convert(5, Nullable`1)")] + [InlineData("int?(null)", typeof(int?), "Convert(null, Nullable`1)")] + [InlineData("string(null)", typeof(string), "Convert(null, String)")] #endif - public void Parse_NullableShouldReturnNullable(string expression, object resultType, object result) - { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; - var sut = new ExpressionParser(parameters, expression, null, null); + public void Parse_NullableShouldReturnNullable(string expression, object resultType, object result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); - // Act - var unaryExpression = (UnaryExpression)sut.Parse(null); + // Act + var unaryExpression = (UnaryExpression)sut.Parse(null); - // Assert - Check.That(unaryExpression.Type).Equals(resultType); - Check.That(unaryExpression.ToString()).Equals(result); + // Assert + Check.That(unaryExpression.Type).Equals(resultType); + Check.That(unaryExpression.ToString()).Equals(result); + } + + [Theory] + [InlineData("it.MainCompany.Name != null", "(company.MainCompany.Name != null)")] + [InlineData("@MainCompany.Companies.Count() > 0", "(company.MainCompany.Companies.Count() > 0)")] + [InlineData("Company.Equals(null, null)", "Equals(null, null)")] + [InlineData("MainCompany.Name", "company.MainCompany.Name")] + [InlineData("Company.Name", "No property or field 'Name' exists in type 'Company'")] + [InlineData("DateTime", "company.DateTime")] + public void Parse_When_PrioritizePropertyOrFieldOverTheType_IsTrue(string expression, string result) + { + // Arrange + var config = new ParsingConfig + { + CustomTypeProvider = _dynamicTypeProviderMock.Object, + PrioritizePropertyOrFieldOverTheType = true + }; + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "company") }; + var sut = new ExpressionParser(parameters, expression, null, config); + + // Act + string parsedExpression; + try + { + parsedExpression = sut.Parse(null).ToString(); } + catch (ParseException e) + { + parsedExpression = e.Message; + } + + // Assert + parsedExpression.Should().Be(result); + } + + [Theory] + [InlineData("it.MainCompany.Name != null", "(company.MainCompany.Name != null)")] + [InlineData("@MainCompany.Companies.Count() > 0", "(company.MainCompany.Companies.Count() > 0)")] + [InlineData("Company.Equals(null, null)", "Equals(null, null)")] + [InlineData("MainCompany.Name", "Static property requires null instance, non-static property requires non-null instance.")] // Exception + [InlineData("DateTime", "'.' or '(' or string literal expected")] // Exception + [InlineData("Company.Name", "Static property requires null instance, non-static property requires non-null instance.")] // Exception + public void Parse_When_PrioritizePropertyOrFieldOverTheType_IsFalse(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "company") }; - [Theory] - [InlineData("it.MainCompany.Name != null", "(company.MainCompany.Name != null)")] - [InlineData("@MainCompany.Companies.Count() > 0", "(company.MainCompany.Companies.Count() > 0)")] - [InlineData("Company.Equals(null, null)", "Equals(null, null)")] - [InlineData("MainCompany.Name", "company.MainCompany.Name")] - [InlineData("Company.Name", "No property or field 'Name' exists in type 'Company'")] - public void Parse_PrioritizePropertyOrFieldOverTheType(string expression, string result) + // Act + string parsedExpression; + try { - // Arrange - ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "company") }; var sut = new ExpressionParser(parameters, expression, null, _parsingConfig); - - // Act - string parsedExpression; - try - { - parsedExpression = sut.Parse(null).ToString(); - } - catch (ParseException e) - { - parsedExpression = e.Message; - } - - // Assert - Check.That(parsedExpression).Equals(result); + parsedExpression = sut.Parse(null).ToString(); } + catch (Exception e) + { + parsedExpression = e.Message; + } + + // Assert + parsedExpression.Should().StartWith(result); } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs index 55b9a1af..46384adb 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.GroupBy.cs @@ -13,7 +13,7 @@ public partial class QueryableTests { public class DateTimeTest { - public DateTimeTest Test { get; set; } + public DateTimeTest? Test { get; set; } public DateTime? D { get; set; } } diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs index ee365db3..82e854d7 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Tests.Helpers.Models; -using FluentAssertions; using Linq.PropertyTranslator.Core; using QueryInterceptor.Core; using Xunit; diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs index 6ce39e54..5a340319 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs @@ -7,283 +7,313 @@ using FluentAssertions; using Xunit; -namespace System.Linq.Dynamic.Core.Tests +namespace System.Linq.Dynamic.Core.Tests; + +public partial class QueryableTests { - public partial class QueryableTests + [Fact] + public void Where_Dynamic() { - [Fact] - public void Where_Dynamic() - { - // Arrange - var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); - var qry = testList.AsQueryable(); - - // Act - var userById = qry.Where("Id=@0", testList[10].Id); - var userByUserName = qry.Where("UserName=\"User5\""); - var nullProfileCount = qry.Where("Profile=null"); - var userByFirstName = qry.Where("Profile!=null && Profile.FirstName=@0", testList[1].Profile.FirstName); - - // Assert - Assert.Equal(testList[10], userById.Single()); - Assert.Equal(testList[5], userByUserName.Single()); - Assert.Equal(testList.Count(x => x.Profile == null), nullProfileCount.Count()); - Assert.Equal(testList[1], userByFirstName.Single()); - } - - [Fact] - public void Where_Dynamic_CheckCastToObject() - { - // Arrange - var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); - var qry = testList.AsQueryable(); - - // Act - string dynamicExpression = qry.Where("Profile == null").Expression.ToDebugView(); - string expresion = qry.Where(var1 => var1.Profile == null).Expression.ToDebugView(); - - // Assert - NFluent.Check.That(dynamicExpression).Equals(expresion); - } - - [Theory] - [InlineData("Fri, 10 May 2019 11:03:17 GMT", 11)] - [InlineData("Fri, 10 May 2019 11:03:17 -07:00", 18)] - public void Where_Dynamic_DateTimeIsParsedAsUTC(string time, int hours) - { - // Arrange - var queryable = new List { - new Example - { - TimeNull = new DateTime(2019, 5, 10, hours, 3, 17, DateTimeKind.Utc) - } - }.AsQueryable(); - - // Act - var parsingConfig = new ParsingConfig + // Arrange + var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); + var qry = testList.AsQueryable(); + + // Act + var userById = qry.Where("Id=@0", testList[10].Id); + var userByUserName = qry.Where("UserName=\"User5\""); + var nullProfileCount = qry.Where("Profile=null"); + var userByFirstName = qry.Where("Profile!=null && Profile.FirstName=@0", testList[1].Profile.FirstName); + + // Assert + Assert.Equal(testList[10], userById.Single()); + Assert.Equal(testList[5], userByUserName.Single()); + Assert.Equal(testList.Count(x => x.Profile == null), nullProfileCount.Count()); + Assert.Equal(testList[1], userByFirstName.Single()); + } + + [Fact] + public void Where_Dynamic_CheckCastToObject() + { + // Arrange + var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); + var qry = testList.AsQueryable(); + + // Act + string dynamicExpression = qry.Where("Profile == null").Expression.ToDebugView(); + string expresion = qry.Where(var1 => var1.Profile == null).Expression.ToDebugView(); + + // Assert + NFluent.Check.That(dynamicExpression).Equals(expresion); + } + + [Theory] + [InlineData("Fri, 10 May 2019 11:03:17 GMT", 11)] + [InlineData("Fri, 10 May 2019 11:03:17 -07:00", 18)] + public void Where_Dynamic_DateTimeIsParsedAsUTC(string time, int hours) + { + // Arrange + var queryable = new List { + new Example { - DateTimeIsParsedAsUTC = true - }; - var result = queryable.Where(parsingConfig, $"it.TimeNull >= \"{time}\""); - - // Assert - Assert.Equal(1, result.Count()); - } - - /// - /// https://github.com/StefH/System.Linq.Dynamic.Core/issues/19 - /// - [Fact] - public void Where_Dynamic_DateTime_NotEquals_Null() + TimeNull = new DateTime(2019, 5, 10, hours, 3, 17, DateTimeKind.Utc) + } + }.AsQueryable(); + + // Act + var parsingConfig = new ParsingConfig { - //Arrange - IQueryable queryable = new[] { new Post() }.AsQueryable(); + DateTimeIsParsedAsUTC = true + }; + var result = queryable.Where(parsingConfig, $"it.TimeNull >= \"{time}\""); - //Act - var expected = queryable.Where(p => p.PostDate != null).ToArray(); - var result1 = queryable.Where("PostDate != null").ToArray(); - var result2 = queryable.Where("null != PostDate").ToArray(); + // Assert + Assert.Equal(1, result.Count()); + } - //Assert - Assert.Equal(expected, result1); - Assert.Equal(expected, result2); - } + /// + /// https://github.com/StefH/System.Linq.Dynamic.Core/issues/19 + /// + [Fact] + public void Where_Dynamic_DateTime_NotEquals_Null() + { + //Arrange + IQueryable queryable = new[] { new Post() }.AsQueryable(); - [Fact] - public void Where_Dynamic_DateTime_Equals_Null() - { - //Arrange - IQueryable queryable = new[] { new Post() }.AsQueryable(); + //Act + var expected = queryable.Where(p => p.PostDate != null).ToArray(); + var result1 = queryable.Where("PostDate != null").ToArray(); + var result2 = queryable.Where("null != PostDate").ToArray(); - //Act - var expected = queryable.Where(p => p.PostDate == null).ToArray(); - var result1 = queryable.Where("PostDate == null").ToArray(); - var result2 = queryable.Where("null == PostDate").ToArray(); + //Assert + Assert.Equal(expected, result1); + Assert.Equal(expected, result2); + } - //Assert - Assert.Equal(expected, result1); - Assert.Equal(expected, result2); - } + [Fact] + public void Where_Dynamic_DateTime_Equals_Null() + { + //Arrange + IQueryable queryable = new[] { new Post() }.AsQueryable(); - [Fact] - public void Where_Dynamic_IQueryable_LambdaExpression() - { - // Arrange - var queryable = (IQueryable)new[] { new User { Income = 5 } }.AsQueryable(); + //Act + var expected = queryable.Where(p => p.PostDate == null).ToArray(); + var result1 = queryable.Where("PostDate == null").ToArray(); + var result2 = queryable.Where("null == PostDate").ToArray(); - Expression> userExpression = u => u.Income > 1; - LambdaExpression lambdaExpression = userExpression; + //Assert + Assert.Equal(expected, result1); + Assert.Equal(expected, result2); + } - // Act - var result = queryable.Where(lambdaExpression).ToDynamicArray(); + [Fact] + public void Where_Dynamic_IQueryable_LambdaExpression() + { + // Arrange + var queryable = (IQueryable)new[] { new User { Income = 5 } }.AsQueryable(); - // Assert - result.Should().HaveCount(1); - } + Expression> userExpression = u => u.Income > 1; + LambdaExpression lambdaExpression = userExpression; - [Fact] - public void Where_Dynamic_IQueryableT_LambdaExpression() - { - // Arrange - var queryable = new[] { new User { Income = 5 } }.AsQueryable(); + // Act + var result = queryable.Where(lambdaExpression).ToDynamicArray(); - Expression> userExpression = u => u.Income > 1; - LambdaExpression lambdaExpression = userExpression; + // Assert + result.Should().HaveCount(1); + } - // Act - var result = queryable.Where(lambdaExpression); + [Fact] + public void Where_Dynamic_IQueryableT_LambdaExpression() + { + // Arrange + var queryable = new[] { new User { Income = 5 } }.AsQueryable(); - // Assert - result.Should().HaveCount(1); - } + Expression> userExpression = u => u.Income > 1; + LambdaExpression lambdaExpression = userExpression; - [Fact] - public void Where_Dynamic_Exceptions() - { - //Arrange - var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); - var qry = testList.AsQueryable(); - - //Act - Assert.Throws(() => qry.Where("Id")); - Assert.Throws(() => qry.Where("Bad=3")); - Assert.Throws(() => qry.Where("Id=123")); - - Assert.Throws(() => DynamicQueryableExtensions.Where(null, "Id=1")); - Assert.Throws(() => qry.Where((string)null)); - Assert.Throws(() => qry.Where("")); - Assert.Throws(() => qry.Where(" ")); - } - - [Fact] - public void Where_Dynamic_StringQuoted() - { - // Arrange - var testList = User.GenerateSampleModels(2, allowNullableProfiles: true); - testList[0].UserName = @"This \""is\"" a test."; - var qry = testList.AsQueryable(); - - // Act - // var result1a = qry.Where(@"UserName == ""This \\""is\\"" a test.""").ToArray(); - var result1b = qry.Where("UserName == \"This \\\\\\\"is\\\\\\\" a test.\"").ToArray(); - var result2a = qry.Where("UserName == @0", @"This \""is\"" a test.").ToArray(); - var result2b = qry.Where("UserName == @0", "This \\\"is\\\" a test.").ToArray(); - - var expected = qry.Where(x => x.UserName == @"This \""is\"" a test.").ToArray(); - - // Assert - Assert.Single(expected); - // Assert.Equal(expected, result1a); - Assert.Equal(expected, result1b); - Assert.Equal(expected, result2a); - Assert.Equal(expected, result2b); - } - - [Fact] - public void Where_Dynamic_EmptyString() - { - // Arrange - var testList = User.GenerateSampleModels(2, allowNullableProfiles: true); - var qry = testList.AsQueryable(); - - // Act - var expected1 = qry.Where(u => u.UserName != string.Empty).ToArray(); - var expected2 = qry.Where(u => u.UserName != "").ToArray(); - var resultDynamic1 = qry.Where("UserName != @0", string.Empty).ToArray(); - var resultDynamic2 = qry.Where("UserName != @0", "").ToArray(); - - // Assert - resultDynamic1.Should().Contain(expected1); - resultDynamic2.Should().Contain(expected2); - } - - [Fact] - public void Where_Dynamic_SelectNewObjects() - { - //Arrange - var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); - var qry = testList.AsQueryable(); + // Act + var result = queryable.Where(lambdaExpression); - //Act - var expectedResult = testList.Where(x => x.Income > 4000).Select(x => new { Id = x.Id, Income = x.Income + 1111 }); - var dynamicList = qry.Where("Income > @0", 4000).ToDynamicList(); + // Assert + result.Should().HaveCount(1); + } - var newUsers = dynamicList.Select(x => new { Id = x.Id, Income = x.Income + 1111 }); - Assert.Equal(newUsers.Cast().ToList(), expectedResult); - } + [Fact] + public void Where_Dynamic_Exceptions() + { + //Arrange + var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); + var qry = testList.AsQueryable(); + + //Act + Assert.Throws(() => qry.Where("Id")); + Assert.Throws(() => qry.Where("Bad=3")); + Assert.Throws(() => qry.Where("Id=123")); + + Assert.Throws(() => DynamicQueryableExtensions.Where(null, "Id=1")); + Assert.Throws(() => qry.Where((string)null)); + Assert.Throws(() => qry.Where("")); + Assert.Throws(() => qry.Where(" ")); + } - [Fact] - public void Where_Dynamic_ExpandoObject_As_Dictionary_Is_Null_Should_Throw_InvalidOperationException() - { - // Arrange - var productsQuery = new[] { new ProductDynamic { ProductId = 1 } }.AsQueryable(); + [Fact] + public void Where_Dynamic_StringQuoted() + { + // Arrange + var testList = User.GenerateSampleModels(2, allowNullableProfiles: true); + testList[0].UserName = @"This \""is\"" a test."; + var qry = testList.AsQueryable(); + + // Act + // var result1a = qry.Where(@"UserName == ""This \\""is\\"" a test.""").ToArray(); + var result1b = qry.Where("UserName == \"This \\\\\\\"is\\\\\\\" a test.\"").ToArray(); + var result2a = qry.Where("UserName == @0", @"This \""is\"" a test.").ToArray(); + var result2b = qry.Where("UserName == @0", "This \\\"is\\\" a test.").ToArray(); + + var expected = qry.Where(x => x.UserName == @"This \""is\"" a test.").ToArray(); + + // Assert + Assert.Single(expected); + // Assert.Equal(expected, result1a); + Assert.Equal(expected, result1b); + Assert.Equal(expected, result2a); + Assert.Equal(expected, result2b); + } - // Act - Action action = () => productsQuery.Where("Properties.Name == @0", "First Product").ToDynamicList(); + [Fact] + public void Where_Dynamic_EmptyString() + { + // Arrange + var testList = User.GenerateSampleModels(2, allowNullableProfiles: true); + var qry = testList.AsQueryable(); + + // Act + var expected1 = qry.Where(u => u.UserName != string.Empty).ToArray(); + var expected2 = qry.Where(u => u.UserName != "").ToArray(); + var resultDynamic1 = qry.Where("UserName != @0", string.Empty).ToArray(); + var resultDynamic2 = qry.Where("UserName != @0", "").ToArray(); + + // Assert + resultDynamic1.Should().Contain(expected1); + resultDynamic2.Should().Contain(expected2); + } - // Assert - action.Should().Throw(); - } + [Fact] + public void Where_Dynamic_SelectNewObjects() + { + //Arrange + var testList = User.GenerateSampleModels(100, allowNullableProfiles: true); + var qry = testList.AsQueryable(); - [Fact(Skip = "NP does not work here")] - public void Where_Dynamic_ExpandoObject_As_Dictionary_Is_Null_With_NullPropagating() - { - // Arrange - var productsQuery = new[] { new ProductDynamic { ProductId = 1 } }.AsQueryable(); + //Act + var expectedResult = testList.Where(x => x.Income > 4000).Select(x => new { Id = x.Id, Income = x.Income + 1111 }); + var dynamicList = qry.Where("Income > @0", 4000).ToDynamicList(); - // Act - var results = productsQuery.Where("np(Properties.Name, \"no\") == @0", "First Product").ToDynamicList(); + var newUsers = dynamicList.Select(x => new { Id = x.Id, Income = x.Income + 1111 }); + Assert.Equal(newUsers.Cast().ToList(), expectedResult); + } - // Assert - results.Should().HaveCount(0); - } + [Fact] + public void Where_Dynamic_ExpandoObject_As_Dictionary_Is_Null_Should_Throw_InvalidOperationException() + { + // Arrange + var productsQuery = new[] { new ProductDynamic { ProductId = 1 } }.AsQueryable(); - [Fact] - public void Where_Dynamic_ExpandoObject_As_Dictionary() - { - // Arrange - var productsQuery = new[] { new ProductDynamic { ProductId = 1, Properties = new Dictionary { { "Name", "test" } } } }.AsQueryable(); + // Act + Action action = () => productsQuery.Where("Properties.Name == @0", "First Product").ToDynamicList(); - // Act - var results = productsQuery.Where("Properties.Name == @0", "test").ToDynamicList(); + // Assert + action.Should().Throw(); + } - // Assert - results.Should().HaveCount(1); - } + [Fact(Skip = "NP does not work here")] + public void Where_Dynamic_ExpandoObject_As_Dictionary_Is_Null_With_NullPropagating() + { + // Arrange + var productsQuery = new[] { new ProductDynamic { ProductId = 1 } }.AsQueryable(); - [Fact] - public void Where_Dynamic_Object_As_Dictionary() - { - // Arrange - var productsQuery = new[] { new ProductDynamic { ProductId = 1, PropertiesAsObject = new Dictionary { { "Name", "test" } } } }.AsQueryable(); + // Act + var results = productsQuery.Where("np(Properties.Name, \"no\") == @0", "First Product").ToDynamicList(); - // Act - var results = productsQuery.Where("PropertiesAsObject.Name == @0", "test").ToDynamicList(); + // Assert + results.Should().HaveCount(0); + } + + [Fact] + public void Where_Dynamic_ExpandoObject_As_Dictionary() + { + // Arrange + var productsQuery = new[] { new ProductDynamic { ProductId = 1, Properties = new Dictionary { { "Name", "test" } } } }.AsQueryable(); - // Assert - results.Should().HaveCount(1); - } + // Act + var results = productsQuery.Where("Properties.Name == @0", "test").ToDynamicList(); - [Fact] - public void Where_Dynamic_ExpandoObject_As_AnonymousType() - { - // Arrange - var productsQuery = new[] { new ProductDynamic { ProductId = 1, Properties = new { Name = "test" } } }.AsQueryable(); + // Assert + results.Should().HaveCount(1); + } + + [Fact] + public void Where_Dynamic_Object_As_Dictionary() + { + // Arrange + var productsQuery = new[] { new ProductDynamic { ProductId = 1, PropertiesAsObject = new Dictionary { { "Name", "test" } } } }.AsQueryable(); + + // Act + var results = productsQuery.Where("PropertiesAsObject.Name == @0", "test").ToDynamicList(); - // Act - var results = productsQuery.Where("Properties.Name == @0", "test").ToDynamicList(); + // Assert + results.Should().HaveCount(1); + } + + [Fact] + public void Where_Dynamic_ExpandoObject_As_AnonymousType() + { + // Arrange + var productsQuery = new[] { new ProductDynamic { ProductId = 1, Properties = new { Name = "test" } } }.AsQueryable(); - // Assert - results.Should().HaveCount(1); - } + // Act + var results = productsQuery.Where("Properties.Name == @0", "test").ToDynamicList(); + + // Assert + results.Should().HaveCount(1); + } - public class ProductDynamic + [Fact] + public void Where_Dynamic_DateTimeConstructor_Issue662() + { + // Arrange + var date = new DateTime(2023, 1, 13, 12, 0, 0); + var queryable = new List { - public int ProductId { get; set; } + new() { DateTime = date }, + new() { DT = date } + }.AsQueryable(); + + // Act 1 + //var result1 = queryable.Where("DT > DateTime(2022, 1, 1, 0, 0, 0)").ToArray(); + + // Assert 1 + //result1.Should().HaveCount(1); + + // Act 2 + var result2 = queryable.Where("it.DateTime > DateTime(2022, 1, 1, 0, 0, 0)").ToArray(); - public dynamic Properties { get; set; } + // Assert 2 + result2.Should().HaveCount(1); + } + + public class ProductDynamic + { + public int ProductId { get; set; } + + public dynamic Properties { get; set; } + + public object PropertiesAsObject { get; set; } + } + + public class Foo + { + public DateTime DT { get; set; } - public object PropertiesAsObject { get; set; } - } + public DateTime DateTime { get; set; } } -} +} \ No newline at end of file From efaa34c34d27e41928eb020ead0a5f09e3bf0bd3 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 5 Feb 2023 11:03:14 +0100 Subject: [PATCH 027/214] Update AbstractDynamicLinqCustomTypeProvider to exclude null types (#665) * Update AbstractDynamicLinqCustomTypeProvider * . * . --- src/Directory.Build.props | 2 +- .../AbstractDynamicLinqCustomTypeProvider.cs | 233 +++++++++--------- .../Extensions/LinqExtensions.cs | 23 +- 3 files changed, 136 insertions(+), 122 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b4e615fc..143e1ce0 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,7 +7,7 @@ Copyright © ZZZ Projects en-us true - 10 + 11 enable logo.png Apache-2.0 diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs index 811b7d10..ffe1ea81 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs @@ -1,155 +1,160 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Dynamic.Core.Extensions; using System.Linq.Dynamic.Core.Validation; using System.Reflection; -namespace System.Linq.Dynamic.Core.CustomTypeProviders +namespace System.Linq.Dynamic.Core.CustomTypeProviders; + +/// +/// The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. +/// +[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] +public abstract class AbstractDynamicLinqCustomTypeProvider { /// - /// The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. + /// Finds the unique types marked with DynamicLinqTypeAttribute. /// - public abstract class AbstractDynamicLinqCustomTypeProvider + /// The assemblies to process. + /// + protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) { - /// - /// Finds the unique types marked with DynamicLinqTypeAttribute. - /// - /// The assemblies to process. - /// - protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) - { - Check.NotNull(assemblies, nameof(assemblies)); + Check.NotNull(assemblies); #if !NET35 - assemblies = assemblies.Where(a => !a.IsDynamic); + assemblies = assemblies.Where(a => !a.IsDynamic); #endif - return GetAssemblyTypesWithDynamicLinqTypeAttribute(assemblies).Distinct().ToArray(); - } + return GetAssemblyTypesWithDynamicLinqTypeAttribute(assemblies).Distinct().ToArray(); + } - /// - /// Resolve any type which is registered in the current application domain. - /// - /// The assemblies to inspect. - /// The typename to resolve. - /// A resolved or null when not found. - protected Type? ResolveType(IEnumerable assemblies, string typeName) - { - Check.NotNull(assemblies, nameof(assemblies)); - Check.NotEmpty(typeName, nameof(typeName)); + /// + /// Resolve any type which is registered in the current application domain. + /// + /// The assemblies to inspect. + /// The typename to resolve. + /// A resolved or null when not found. + protected Type? ResolveType(IEnumerable assemblies, string typeName) + { + Check.NotNull(assemblies); + Check.NotEmpty(typeName); - foreach (var assembly in assemblies) + foreach (var assembly in assemblies) + { + var resolvedType = assembly.GetType(typeName, false, true); + if (resolvedType != null) { - Type resolvedType = assembly.GetType(typeName, false, true); - if (resolvedType != null) - { - return resolvedType; - } + return resolvedType; } - - return null; } - /// - /// Resolve a type by the simple name which is registered in the current application domain. - /// - /// The assemblies to inspect. - /// The simple typename to resolve. - /// A resolved or null when not found. - protected Type? ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) + return null; + } + + /// + /// Resolve a type by the simple name which is registered in the current application domain. + /// + /// The assemblies to inspect. + /// The simple typename to resolve. + /// A resolved or null when not found. + protected Type? ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) + { + Check.NotNull(assemblies); + Check.NotEmpty(simpleTypeName); + + foreach (var assembly in assemblies) { - Check.NotNull(assemblies, nameof(assemblies)); - Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); + var fullNames = assembly.GetTypes().Select(t => t.FullName!).Distinct(); + var firstMatchingFullname = fullNames.FirstOrDefault(fn => fn.EndsWith($".{simpleTypeName}")); - foreach (var assembly in assemblies) + if (firstMatchingFullname != null) { - var fullNames = assembly.GetTypes().Select(t => t.FullName!).Distinct(); - var firstMatchingFullname = fullNames.FirstOrDefault(fn => fn.EndsWith($".{simpleTypeName}")); - - if (firstMatchingFullname != null) + var resolvedType = assembly.GetType(firstMatchingFullname, false, true); + if (resolvedType != null) { - var resolvedType = assembly.GetType(firstMatchingFullname, false, true); - if (resolvedType != null) - { - return resolvedType; - } + return resolvedType; } } - - return null; } + return null; + } + #if (WINDOWS_APP || UAP10_0 || NETSTANDARD) - /// - /// Gets the assembly types annotated with in an Exception friendly way. - /// - /// The assemblies to process. - /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + /// + /// Gets the assembly types annotated with in an Exception friendly way. + /// + /// The assemblies to process. + /// + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + { + Check.NotNull(assemblies); + + foreach (var assembly in assemblies) { - Check.NotNull(assemblies, nameof(assemblies)); + var definedTypes = Type.EmptyTypes; - foreach (var assembly in assemblies) + try + { + definedTypes = assembly.ExportedTypes.ToArray(); + } + catch (ReflectionTypeLoadException reflectionTypeLoadException) + { + definedTypes = reflectionTypeLoadException.Types.WhereNotNull().ToArray(); + } + catch { - Type[]? definedTypes = null; + // Ignore all other exceptions + } - try - { - definedTypes = assembly.ExportedTypes.Where(t => t.GetTypeInfo().IsDefined(typeof(DynamicLinqTypeAttribute), false)).ToArray(); - } - catch (ReflectionTypeLoadException reflectionTypeLoadException) - { - definedTypes = reflectionTypeLoadException.Types; - } - catch - { - // Ignore all other exceptions - } + var filteredAndDistinct = definedTypes + .Where(t => t.GetTypeInfo().IsDefined(typeof(DynamicLinqTypeAttribute), false)) + .Distinct(); - if (definedTypes != null && definedTypes.Length > 0) - { - foreach (var definedType in definedTypes) - { - yield return definedType; - } - } + foreach (var definedType in filteredAndDistinct) + { + yield return definedType; } } + } #else - /// - /// Gets the assembly types annotated with in an Exception friendly way. - /// - /// The assemblies to process. - /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + /// + /// Gets the assembly types annotated with in an Exception friendly way. + /// + /// The assemblies to process. + /// + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + { + Check.NotNull(assemblies); + +#if !NET5_0_OR_GREATER + assemblies = assemblies.Where(a => !a.GlobalAssemblyCache); // Skip System DLL's +#endif + + foreach (var assembly in assemblies) { - Check.NotNull(assemblies, nameof(assemblies)); + var definedTypes = Type.EmptyTypes; - foreach (var assembly in assemblies.Where(a => !a.GlobalAssemblyCache)) // Skip System DLL's + try { - Type[]? definedTypes = null; + definedTypes = assembly.GetExportedTypes().ToArray(); + } + catch (ReflectionTypeLoadException reflectionTypeLoadException) + { + definedTypes = reflectionTypeLoadException.Types.WhereNotNull().ToArray(); + } + catch + { + // Ignore all other exceptions + } - try - { - definedTypes = assembly - .GetExportedTypes() - .Where(t => t.IsDefined(typeof(DynamicLinqTypeAttribute), false)) - .ToArray(); - } - catch (ReflectionTypeLoadException reflectionTypeLoadException) - { - definedTypes = reflectionTypeLoadException.Types; - } - catch - { - // Ignore all other exceptions - } + var filteredAndDistinct = definedTypes + .Where(t => t.IsDefined(typeof(DynamicLinqTypeAttribute), false)) + .Distinct(); - if (definedTypes != null && definedTypes.Length > 0) - { - foreach (var definedType in definedTypes) - { - yield return definedType; - } - } + foreach (var definedType in filteredAndDistinct) + { + yield return definedType; } } -#endif } -} +#endif +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs b/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs index a0c0a5f3..c68ffee3 100644 --- a/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs +++ b/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs @@ -1,13 +1,22 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Dynamic.Core.Validation; -namespace System.Linq.Dynamic.Core.Extensions +namespace System.Linq.Dynamic.Core.Extensions; + +[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] +internal static class LinqExtensions { - internal static class LinqExtensions + // Ex: collection.TakeLast(5); + public static IEnumerable TakeLast(this IList source, int n) { - // Ex: collection.TakeLast(5); - public static IEnumerable TakeLast(this IList source, int n) - { - return source.Skip(Math.Max(0, source.Count() - n)); - } + return source.Skip(Math.Max(0, source.Count() - n)); + } + + public static IEnumerable WhereNotNull(this IEnumerable sequence) + { + Check.NotNull(sequence); + + return sequence.Where(e => e != null)!; } } \ No newline at end of file From 6c7872d4e6c294b1e6dd6b5f4683af685b5e70ea Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 5 Feb 2023 14:32:12 +0100 Subject: [PATCH 028/214] Fixed ExpressionParser when WrappedValue-string is used for equals-operator (#666) * UT * ? * Fixed ExpressionParser when WrappedValue-string is used for equals-operator --- .../Nullable/NotNullWhenAttribute.cs | 56 + .../Parser/ConstantExpressionWrapper.cs | 384 +- .../Parser/ExpressionHelper.cs | 567 +-- .../Parser/ExpressionParser.cs | 3299 +++++++++-------- .../Parser/IConstantExpressionWrapper.cs | 16 +- .../Parser/IExpressionHelper.cs | 50 +- .../SupportedOperands/IEqualitySignatures.cs | 37 +- .../Parser/WrappedValue.cs | 17 +- ...ts.UseParameterizedNamesInDynamicQuery .cs | 85 + 9 files changed, 2343 insertions(+), 2168 deletions(-) create mode 100644 src/System.Linq.Dynamic.Core/Compatibility/Nullable/NotNullWhenAttribute.cs create mode 100644 test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs diff --git a/src/System.Linq.Dynamic.Core/Compatibility/Nullable/NotNullWhenAttribute.cs b/src/System.Linq.Dynamic.Core/Compatibility/Nullable/NotNullWhenAttribute.cs new file mode 100644 index 00000000..676ef898 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Compatibility/Nullable/NotNullWhenAttribute.cs @@ -0,0 +1,56 @@ +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if NETSTANDARD1_3_OR_GREATER || NET35 || NET40 || NET45 || NET452 || NET46 || NETCOREAPP2_1 || UAP10_0 + +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis; + +/// +/// Specifies that when a method returns , +/// the parameter will not be even if the corresponding type allows it. +/// +[AttributeUsage(AttributeTargets.Parameter)] +[DebuggerNonUserCode] +internal sealed class NotNullWhenAttribute : Attribute +{ + /// + /// Gets the return value condition. + /// If the method returns this value, the associated parameter will not be . + /// + public bool ReturnValue { get; } + + /// + /// Initializes the attribute with the specified return value condition. + /// + /// + /// The return value condition. + /// If the method returns this value, the associated parameter will not be . + /// + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } +} +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs index 7b3e403b..201afbf6 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs @@ -1,199 +1,213 @@ -using System.Linq.Expressions; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +#if UAP10_0 || NETSTANDARD1_3 using System.Reflection; +#endif -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +/// +/// Based on gblog by graeme-hill. https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd +/// +internal class ConstantExpressionWrapper : IConstantExpressionWrapper { - /// - /// Based on gblog by graeme-hill. https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd - /// - internal class ConstantExpressionWrapper : IConstantExpressionWrapper + public void Wrap(ref Expression expression) { - public void Wrap(ref Expression expression) + if (expression is ConstantExpression constantExpression) { - if (expression is ConstantExpression constantExpression) - { - if (constantExpression.Type == typeof(bool)) - { - expression = WrappedConstant((bool)constantExpression.Value); - } - else if (constantExpression.Type == typeof(bool?)) - { - expression = WrappedConstant((bool?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(char)) - { - expression = WrappedConstant((char)constantExpression.Value); - } - else if (constantExpression.Type == typeof(char?)) - { - expression = WrappedConstant((char?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(byte)) - { - expression = WrappedConstant((byte)constantExpression.Value); - } - else if (constantExpression.Type == typeof(byte?)) - { - expression = WrappedConstant((byte?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(sbyte)) - { - expression = WrappedConstant((sbyte)constantExpression.Value); - } - else if (constantExpression.Type == typeof(string)) - { - expression = WrappedConstant((string)constantExpression.Value); - } - else if (constantExpression.Type == typeof(float)) - { - expression = WrappedConstant((float)constantExpression.Value); - } - else if (constantExpression.Type == typeof(float?)) - { - expression = WrappedConstant((float?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(decimal)) - { - expression = WrappedConstant((decimal)constantExpression.Value); - } - else if (constantExpression.Type == typeof(decimal?)) - { - expression = WrappedConstant((decimal?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(double)) - { - expression = WrappedConstant((double)constantExpression.Value); - } - else if (constantExpression.Type == typeof(double?)) - { - expression = WrappedConstant((double?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(long)) - { - expression = WrappedConstant((long)constantExpression.Value); - } - else if (constantExpression.Type == typeof(long?)) - { - expression = WrappedConstant((long?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(ulong)) - { - expression = WrappedConstant((ulong)constantExpression.Value); - } - else if (constantExpression.Type == typeof(ulong?)) - { - expression = WrappedConstant((ulong?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(int)) - { - expression = WrappedConstant((int)constantExpression.Value); - } - else if (constantExpression.Type == typeof(int?)) - { - expression = WrappedConstant((int?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(uint)) - { - expression = WrappedConstant((uint)constantExpression.Value); - } - else if (constantExpression.Type == typeof(uint?)) - { - expression = WrappedConstant((uint?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(short)) - { - expression = WrappedConstant((short)constantExpression.Value); - } - else if (constantExpression.Type == typeof(short?)) - { - expression = WrappedConstant((short?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(ushort)) - { - expression = WrappedConstant((ushort)constantExpression.Value); - } - else if (constantExpression.Type == typeof(ushort?)) - { - expression = WrappedConstant((ushort?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(Guid)) - { - expression = WrappedConstant((Guid)constantExpression.Value); - } - else if (constantExpression.Type == typeof(Guid?)) - { - expression = WrappedConstant((Guid?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(DateTime)) - { - expression = WrappedConstant((DateTime)constantExpression.Value); - } - else if (constantExpression.Type == typeof(DateTime?)) - { - expression = WrappedConstant((DateTime?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(DateTimeOffset)) - { - expression = WrappedConstant((DateTimeOffset)constantExpression.Value); - } - else if (constantExpression.Type == typeof(DateTimeOffset?)) - { - expression = WrappedConstant((DateTimeOffset?)constantExpression.Value); - } - else if (constantExpression.Type == typeof(TimeSpan)) - { - expression = WrappedConstant((TimeSpan)constantExpression.Value); - } - else if (constantExpression.Type == typeof(TimeSpan?)) - { - expression = WrappedConstant((TimeSpan?)constantExpression.Value); - } - - return; + if (constantExpression.Type == typeof(bool)) + { + expression = Wrap((bool)constantExpression.Value); } - - if (expression is NewExpression newExpression) - { - if (newExpression.Type == typeof(Guid)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(Guid?)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(DateTime)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(DateTime?)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(DateTimeOffset)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(DateTimeOffset?)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(TimeSpan)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } - else if (newExpression.Type == typeof(TimeSpan?)) - { - expression = WrappedConstant(Expression.Lambda>(newExpression).Compile()()); - } + else if (constantExpression.Type == typeof(bool?)) + { + expression = Wrap((bool?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(char)) + { + expression = Wrap((char)constantExpression.Value); + } + else if (constantExpression.Type == typeof(char?)) + { + expression = Wrap((char?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(byte)) + { + expression = Wrap((byte)constantExpression.Value); + } + else if (constantExpression.Type == typeof(byte?)) + { + expression = Wrap((byte?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(sbyte)) + { + expression = Wrap((sbyte)constantExpression.Value); + } + else if (constantExpression.Type == typeof(string)) + { + expression = Wrap((string)constantExpression.Value); + } + else if (constantExpression.Type == typeof(float)) + { + expression = Wrap((float)constantExpression.Value); + } + else if (constantExpression.Type == typeof(float?)) + { + expression = Wrap((float?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(decimal)) + { + expression = Wrap((decimal)constantExpression.Value); + } + else if (constantExpression.Type == typeof(decimal?)) + { + expression = Wrap((decimal?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(double)) + { + expression = Wrap((double)constantExpression.Value); + } + else if (constantExpression.Type == typeof(double?)) + { + expression = Wrap((double?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(long)) + { + expression = Wrap((long)constantExpression.Value); + } + else if (constantExpression.Type == typeof(long?)) + { + expression = Wrap((long?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(ulong)) + { + expression = Wrap((ulong)constantExpression.Value); + } + else if (constantExpression.Type == typeof(ulong?)) + { + expression = Wrap((ulong?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(int)) + { + expression = Wrap((int)constantExpression.Value); + } + else if (constantExpression.Type == typeof(int?)) + { + expression = Wrap((int?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(uint)) + { + expression = Wrap((uint)constantExpression.Value); + } + else if (constantExpression.Type == typeof(uint?)) + { + expression = Wrap((uint?)constantExpression.Value); } + else if (constantExpression.Type == typeof(short)) + { + expression = Wrap((short)constantExpression.Value); + } + else if (constantExpression.Type == typeof(short?)) + { + expression = Wrap((short?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(ushort)) + { + expression = Wrap((ushort)constantExpression.Value); + } + else if (constantExpression.Type == typeof(ushort?)) + { + expression = Wrap((ushort?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(Guid)) + { + expression = Wrap((Guid)constantExpression.Value); + } + else if (constantExpression.Type == typeof(Guid?)) + { + expression = Wrap((Guid?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(DateTime)) + { + expression = Wrap((DateTime)constantExpression.Value); + } + else if (constantExpression.Type == typeof(DateTime?)) + { + expression = Wrap((DateTime?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(DateTimeOffset)) + { + expression = Wrap((DateTimeOffset)constantExpression.Value); + } + else if (constantExpression.Type == typeof(DateTimeOffset?)) + { + expression = Wrap((DateTimeOffset?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(TimeSpan)) + { + expression = Wrap((TimeSpan)constantExpression.Value); + } + else if (constantExpression.Type == typeof(TimeSpan?)) + { + expression = Wrap((TimeSpan?)constantExpression.Value); + } + + return; } - private static MemberExpression WrappedConstant(TValue value) + if (expression is NewExpression newExpression) { - var wrapper = new WrappedValue(value); + if (newExpression.Type == typeof(Guid)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(Guid?)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(DateTime)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(DateTime?)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(DateTimeOffset)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(DateTimeOffset?)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(TimeSpan)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(TimeSpan?)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + } + } - return Expression.Property(Expression.Constant(wrapper), typeof(WrappedValue).GetProperty("Value")!); + public bool TryUnwrap(MemberExpression? expression, [NotNullWhen(true)] out TValue? value) + { + if (expression?.Expression is ConstantExpression { Value: WrappedValue wrapper }) + { + value = wrapper.Value!; + return true; } + + value = default; + return false; + } + + private static MemberExpression Wrap(TValue value) + { + var wrapper = new WrappedValue(value); + + return Expression.Property(Expression.Constant(wrapper), typeof(WrappedValue).GetProperty("Value")!); } } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs index 2a8dc419..5900e037 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs @@ -1,209 +1,221 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal class ExpressionHelper : IExpressionHelper { - internal class ExpressionHelper : IExpressionHelper + private readonly IConstantExpressionWrapper _constantExpressionWrapper = new ConstantExpressionWrapper(); + private readonly ParsingConfig _parsingConfig; + + internal ExpressionHelper(ParsingConfig parsingConfig) { - private readonly IConstantExpressionWrapper _constantExpressionWrapper = new ConstantExpressionWrapper(); - private readonly ParsingConfig _parsingConfig; + _parsingConfig = Check.NotNull(parsingConfig); + } - internal ExpressionHelper(ParsingConfig parsingConfig) + public void WrapConstantExpression(ref Expression argument) + { + if (_parsingConfig.UseParameterizedNamesInDynamicQuery) { - _parsingConfig = Check.NotNull(parsingConfig); + _constantExpressionWrapper.Wrap(ref argument); } + } - public void WrapConstantExpression(ref Expression argument) + public bool TryUnwrapConstantExpression(Expression? expression, [NotNullWhen(true)] out TValue? value) + { + if (_parsingConfig.UseParameterizedNamesInDynamicQuery && _constantExpressionWrapper.TryUnwrap(expression as MemberExpression, out value)) { - if (_parsingConfig.UseParameterizedNamesInDynamicQuery) - { - _constantExpressionWrapper.Wrap(ref argument); - } + return true; } - public void ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref Expression left, ref Expression right) - { - if (left.Type == right.Type) - { - return; - } + value = default; + return false; + } - if (left.Type == typeof(ulong) || right.Type == typeof(ulong)) - { - right = right.Type != typeof(ulong) ? Expression.Convert(right, typeof(ulong)) : right; - left = left.Type != typeof(ulong) ? Expression.Convert(left, typeof(ulong)) : left; - } - else if (left.Type == typeof(long) || right.Type == typeof(long)) - { - right = right.Type != typeof(long) ? Expression.Convert(right, typeof(long)) : right; - left = left.Type != typeof(long) ? Expression.Convert(left, typeof(long)) : left; - } - else if (left.Type == typeof(uint) || right.Type == typeof(uint)) - { - right = right.Type != typeof(uint) ? Expression.Convert(right, typeof(uint)) : right; - left = left.Type != typeof(uint) ? Expression.Convert(left, typeof(uint)) : left; - } - else if (left.Type == typeof(int) || right.Type == typeof(int)) - { - right = right.Type != typeof(int) ? Expression.Convert(right, typeof(int)) : right; - left = left.Type != typeof(int) ? Expression.Convert(left, typeof(int)) : left; - } - else if (left.Type == typeof(ushort) || right.Type == typeof(ushort)) - { - right = right.Type != typeof(ushort) ? Expression.Convert(right, typeof(ushort)) : right; - left = left.Type != typeof(ushort) ? Expression.Convert(left, typeof(ushort)) : left; - } - else if (left.Type == typeof(short) || right.Type == typeof(short)) - { - right = right.Type != typeof(short) ? Expression.Convert(right, typeof(short)) : right; - left = left.Type != typeof(short) ? Expression.Convert(left, typeof(short)) : left; - } - else if (left.Type == typeof(byte) || right.Type == typeof(byte)) - { - right = right.Type != typeof(byte) ? Expression.Convert(right, typeof(byte)) : right; - left = left.Type != typeof(byte) ? Expression.Convert(left, typeof(byte)) : left; - } + public void ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref Expression left, ref Expression right) + { + if (left.Type == right.Type) + { + return; } - public Expression GenerateAdd(Expression left, Expression right) + if (left.Type == typeof(ulong) || right.Type == typeof(ulong)) { - return Expression.Add(left, right); + right = right.Type != typeof(ulong) ? Expression.Convert(right, typeof(ulong)) : right; + left = left.Type != typeof(ulong) ? Expression.Convert(left, typeof(ulong)) : left; } - - public Expression GenerateStringConcat(Expression left, Expression right) + else if (left.Type == typeof(long) || right.Type == typeof(long)) { - return GenerateStaticMethodCall("Concat", left, right); + right = right.Type != typeof(long) ? Expression.Convert(right, typeof(long)) : right; + left = left.Type != typeof(long) ? Expression.Convert(left, typeof(long)) : left; } - - public Expression GenerateSubtract(Expression left, Expression right) + else if (left.Type == typeof(uint) || right.Type == typeof(uint)) { - return Expression.Subtract(left, right); + right = right.Type != typeof(uint) ? Expression.Convert(right, typeof(uint)) : right; + left = left.Type != typeof(uint) ? Expression.Convert(left, typeof(uint)) : left; } - - public Expression GenerateEqual(Expression left, Expression right) + else if (left.Type == typeof(int) || right.Type == typeof(int)) + { + right = right.Type != typeof(int) ? Expression.Convert(right, typeof(int)) : right; + left = left.Type != typeof(int) ? Expression.Convert(left, typeof(int)) : left; + } + else if (left.Type == typeof(ushort) || right.Type == typeof(ushort)) + { + right = right.Type != typeof(ushort) ? Expression.Convert(right, typeof(ushort)) : right; + left = left.Type != typeof(ushort) ? Expression.Convert(left, typeof(ushort)) : left; + } + else if (left.Type == typeof(short) || right.Type == typeof(short)) { - OptimizeForEqualityIfPossible(ref left, ref right); + right = right.Type != typeof(short) ? Expression.Convert(right, typeof(short)) : right; + left = left.Type != typeof(short) ? Expression.Convert(left, typeof(short)) : left; + } + else if (left.Type == typeof(byte) || right.Type == typeof(byte)) + { + right = right.Type != typeof(byte) ? Expression.Convert(right, typeof(byte)) : right; + left = left.Type != typeof(byte) ? Expression.Convert(left, typeof(byte)) : left; + } + } - WrapConstantExpressions(ref left, ref right); + public Expression GenerateAdd(Expression left, Expression right) + { + return Expression.Add(left, right); + } - return Expression.Equal(left, right); - } + public Expression GenerateStringConcat(Expression left, Expression right) + { + return GenerateStaticMethodCall("Concat", left, right); + } - public Expression GenerateNotEqual(Expression left, Expression right) - { - OptimizeForEqualityIfPossible(ref left, ref right); + public Expression GenerateSubtract(Expression left, Expression right) + { + return Expression.Subtract(left, right); + } - WrapConstantExpressions(ref left, ref right); + public Expression GenerateEqual(Expression left, Expression right) + { + OptimizeForEqualityIfPossible(ref left, ref right); - return Expression.NotEqual(left, right); - } + WrapConstantExpressions(ref left, ref right); - public Expression GenerateGreaterThan(Expression left, Expression right) - { - if (left.Type == typeof(string)) - { - return Expression.GreaterThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); - } + return Expression.Equal(left, right); + } - if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) - { - var leftPart = left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left; - var rightPart = right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right; - return Expression.GreaterThan(leftPart, rightPart); - } + public Expression GenerateNotEqual(Expression left, Expression right) + { + OptimizeForEqualityIfPossible(ref left, ref right); + + WrapConstantExpressions(ref left, ref right); - WrapConstantExpressions(ref left, ref right); + return Expression.NotEqual(left, right); + } - return Expression.GreaterThan(left, right); + public Expression GenerateGreaterThan(Expression left, Expression right) + { + if (left.Type == typeof(string)) + { + return Expression.GreaterThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } - public Expression GenerateGreaterThanEqual(Expression left, Expression right) + if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) { - if (left.Type == typeof(string)) - { - return Expression.GreaterThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); - } + var leftPart = left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left; + var rightPart = right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right; + return Expression.GreaterThan(leftPart, rightPart); + } - if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) - { - return Expression.GreaterThanOrEqual(left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left, - right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right); - } + WrapConstantExpressions(ref left, ref right); - WrapConstantExpressions(ref left, ref right); + return Expression.GreaterThan(left, right); + } - return Expression.GreaterThanOrEqual(left, right); + public Expression GenerateGreaterThanEqual(Expression left, Expression right) + { + if (left.Type == typeof(string)) + { + return Expression.GreaterThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } - public Expression GenerateLessThan(Expression left, Expression right) + if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) { - if (left.Type == typeof(string)) - { - return Expression.LessThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); - } + return Expression.GreaterThanOrEqual(left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left, + right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right); + } - if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) - { - return Expression.LessThan(left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left, - right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right); - } + WrapConstantExpressions(ref left, ref right); - WrapConstantExpressions(ref left, ref right); + return Expression.GreaterThanOrEqual(left, right); + } - return Expression.LessThan(left, right); + public Expression GenerateLessThan(Expression left, Expression right) + { + if (left.Type == typeof(string)) + { + return Expression.LessThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } - public Expression GenerateLessThanEqual(Expression left, Expression right) + if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) { - if (left.Type == typeof(string)) - { - return Expression.LessThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); - } + return Expression.LessThan(left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left, + right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right); + } - if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) - { - return Expression.LessThanOrEqual(left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left, - right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right); - } + WrapConstantExpressions(ref left, ref right); - WrapConstantExpressions(ref left, ref right); + return Expression.LessThan(left, right); + } - return Expression.LessThanOrEqual(left, right); + public Expression GenerateLessThanEqual(Expression left, Expression right) + { + if (left.Type == typeof(string)) + { + return Expression.LessThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } - public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression right) + if (left.Type.GetTypeInfo().IsEnum || right.Type.GetTypeInfo().IsEnum) { - // The goal here is to provide the way to convert some types from the string form in a way that is compatible with Linq to Entities. - // The Expression.Call(typeof(Guid).GetMethod("Parse"), right); does the job only for Linq to Object but Linq to Entities. - Type leftType = left.Type; - Type rightType = right.Type; + return Expression.LessThanOrEqual(left.Type.GetTypeInfo().IsEnum ? Expression.Convert(left, Enum.GetUnderlyingType(left.Type)) : left, + right.Type.GetTypeInfo().IsEnum ? Expression.Convert(right, Enum.GetUnderlyingType(right.Type)) : right); + } - if (rightType == typeof(string) && right.NodeType == ExpressionType.Constant) - { - right = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)right).Value, leftType) ?? right; - } + WrapConstantExpressions(ref left, ref right); - if (leftType == typeof(string) && left.NodeType == ExpressionType.Constant) - { - left = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)left).Value, rightType) ?? left; - } + return Expression.LessThanOrEqual(left, right); + } + + public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression right) + { + // The goal here is to provide the way to convert some types from the string form in a way that is compatible with Linq to Entities. + // The Expression.Call(typeof(Guid).GetMethod("Parse"), right); does the job only for Linq to Object but Linq to Entities. + Type leftType = left.Type; + Type rightType = right.Type; + + if (rightType == typeof(string) && right.NodeType == ExpressionType.Constant) + { + right = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)right).Value, leftType) ?? right; } - public Expression? OptimizeStringForEqualityIfPossible(string? text, Type type) + if (leftType == typeof(string) && left.NodeType == ExpressionType.Constant) { - if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) - { - return Expression.Constant(dateTime, typeof(DateTime)); - } + left = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)left).Value, rightType) ?? left; + } + } + + public Expression? OptimizeStringForEqualityIfPossible(string? text, Type type) + { + if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) + { + return Expression.Constant(dateTime, typeof(DateTime)); + } #if !NET35 - if (type == typeof(Guid) && Guid.TryParse(text, out Guid guid)) - { - return Expression.Constant(guid, typeof(Guid)); - } + if (type == typeof(Guid) && Guid.TryParse(text, out Guid guid)) + { + return Expression.Constant(guid, typeof(Guid)); + } #else try { @@ -214,191 +226,190 @@ public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression ri // Doing it in old fashion way when no TryParse interface was provided by .NET } #endif - return null; - } + return null; + } - public bool MemberExpressionIsDynamic(Expression expression) - { + public bool MemberExpressionIsDynamic(Expression expression) + { #if NET35 return false; #else - return expression is MemberExpression memberExpression && memberExpression.Member.GetCustomAttribute() != null; + return expression is MemberExpression memberExpression && memberExpression.Member.GetCustomAttribute() != null; #endif - } + } - public Expression ConvertToExpandoObjectAndCreateDynamicExpression(Expression expression, Type type, string propertyName) - { + public Expression ConvertToExpandoObjectAndCreateDynamicExpression(Expression expression, Type type, string propertyName) + { #if !NET35 && !UAP10_0 && !NETSTANDARD1_3 - return Expression.Dynamic(new DynamicGetMemberBinder(propertyName, _parsingConfig), type, expression); + return Expression.Dynamic(new DynamicGetMemberBinder(propertyName, _parsingConfig), type, expression); #else throw new NotSupportedException(Res.DynamicExpandoObjectIsNotSupported); #endif - } + } - private MethodInfo GetStaticMethod(string methodName, Expression left, Expression right) + private MethodInfo GetStaticMethod(string methodName, Expression left, Expression right) + { + var methodInfo = left.Type.GetMethod(methodName, new[] { left.Type, right.Type }); + if (methodInfo == null) { - var methodInfo = left.Type.GetMethod(methodName, new[] { left.Type, right.Type }); - if (methodInfo == null) - { - methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type })!; - } - - return methodInfo; + methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type })!; } - private Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) - { - return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right }); - } + return methodInfo; + } - private void WrapConstantExpressions(ref Expression left, ref Expression right) - { - if (_parsingConfig.UseParameterizedNamesInDynamicQuery) - { - _constantExpressionWrapper.Wrap(ref left); - _constantExpressionWrapper.Wrap(ref right); - } - } + private Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) + { + return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right }); + } - public bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, bool addSelf, out Expression generatedExpression) + private void WrapConstantExpressions(ref Expression left, ref Expression right) + { + if (_parsingConfig.UseParameterizedNamesInDynamicQuery) { - var expressions = CollectExpressions(addSelf, sourceExpression); - - if (expressions.Count == 1 && !(expressions[0] is MethodCallExpression)) - { - generatedExpression = sourceExpression; - return false; - } + _constantExpressionWrapper.Wrap(ref left); + _constantExpressionWrapper.Wrap(ref right); + } + } - // Reverse the list - expressions.Reverse(); + public bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, bool addSelf, out Expression generatedExpression) + { + var expressions = CollectExpressions(addSelf, sourceExpression); - // Convert all expressions into '!= null' expressions (only if the type can be null) - var binaryExpressions = expressions - .Where(expression => TypeHelper.TypeCanBeNull(expression.Type)) - .Select(expression => Expression.NotEqual(expression, Expression.Constant(null))) - .ToArray(); + if (expressions.Count == 1 && !(expressions[0] is MethodCallExpression)) + { + generatedExpression = sourceExpression; + return false; + } - // Convert all binary expressions into `AndAlso(...)` - generatedExpression = binaryExpressions[0]; - for (int i = 1; i < binaryExpressions.Length; i++) - { - generatedExpression = Expression.AndAlso(generatedExpression, binaryExpressions[i]); - } + // Reverse the list + expressions.Reverse(); - return true; - } + // Convert all expressions into '!= null' expressions (only if the type can be null) + var binaryExpressions = expressions + .Where(expression => TypeHelper.TypeCanBeNull(expression.Type)) + .Select(expression => Expression.NotEqual(expression, Expression.Constant(null))) + .ToArray(); - public bool ExpressionQualifiesForNullPropagation(Expression? expression) + // Convert all binary expressions into `AndAlso(...)` + generatedExpression = binaryExpressions[0]; + for (int i = 1; i < binaryExpressions.Length; i++) { - return - expression is MemberExpression || - expression is ParameterExpression || - expression is MethodCallExpression || - expression is UnaryExpression; + generatedExpression = Expression.AndAlso(generatedExpression, binaryExpressions[i]); } - public Expression GenerateDefaultExpression(Type type) - { + return true; + } + + public bool ExpressionQualifiesForNullPropagation(Expression? expression) + { + return + expression is MemberExpression || + expression is ParameterExpression || + expression is MethodCallExpression || + expression is UnaryExpression; + } + + public Expression GenerateDefaultExpression(Type type) + { #if NET35 return Expression.Constant(Activator.CreateInstance(type)); #else - return Expression.Default(type); + return Expression.Default(type); #endif + } + + private Expression? GetMemberExpression(Expression? expression) + { + if (ExpressionQualifiesForNullPropagation(expression)) + { + return expression; } - private Expression? GetMemberExpression(Expression? expression) + if (expression is LambdaExpression lambdaExpression) { - if (ExpressionQualifiesForNullPropagation(expression)) + if (lambdaExpression.Body is MemberExpression bodyAsMemberExpression) { - return expression; + return bodyAsMemberExpression; } - if (expression is LambdaExpression lambdaExpression) + if (lambdaExpression.Body is UnaryExpression bodyAsUnaryExpression) { - if (lambdaExpression.Body is MemberExpression bodyAsMemberExpression) - { - return bodyAsMemberExpression; - } - - if (lambdaExpression.Body is UnaryExpression bodyAsUnaryExpression) - { - return bodyAsUnaryExpression.Operand; - } + return bodyAsUnaryExpression.Operand; } - - return null; } - private List CollectExpressions(bool addSelf, Expression sourceExpression) - { - Expression? expression = GetMemberExpression(sourceExpression); + return null; + } - var list = new List(); + private List CollectExpressions(bool addSelf, Expression sourceExpression) + { + Expression? expression = GetMemberExpression(sourceExpression); - if (addSelf) - { - switch (expression) - { - case MemberExpression _: - list.Add(sourceExpression); - break; - - // ReSharper disable once RedundantEmptySwitchSection - default: - break; - } - } + var list = new List(); - bool expressionRecognized; - do + if (addSelf) + { + switch (expression) { - switch (expression) - { - case MemberExpression memberExpression: - expression = GetMemberExpression(memberExpression.Expression); - expressionRecognized = expression != null; - break; - - case MethodCallExpression methodCallExpression: - expression = GetMethodCallExpression(methodCallExpression); - expressionRecognized = expression != null; - break; - - case UnaryExpression unaryExpression: - expression = GetUnaryExpression(unaryExpression); - expressionRecognized = expression != null; - break; - - default: - expressionRecognized = false; - break; - } - - if (expressionRecognized && ExpressionQualifiesForNullPropagation(expression)) - { - list.Add(expression!); - } - } while (expressionRecognized); - - return list; + case MemberExpression _: + list.Add(sourceExpression); + break; + + // ReSharper disable once RedundantEmptySwitchSection + default: + break; + } } - private static Expression? GetMethodCallExpression(MethodCallExpression methodCallExpression) + bool expressionRecognized; + do { - if (methodCallExpression.Object != null) + switch (expression) + { + case MemberExpression memberExpression: + expression = GetMemberExpression(memberExpression.Expression); + expressionRecognized = expression != null; + break; + + case MethodCallExpression methodCallExpression: + expression = GetMethodCallExpression(methodCallExpression); + expressionRecognized = expression != null; + break; + + case UnaryExpression unaryExpression: + expression = GetUnaryExpression(unaryExpression); + expressionRecognized = expression != null; + break; + + default: + expressionRecognized = false; + break; + } + + if (expressionRecognized && ExpressionQualifiesForNullPropagation(expression)) { - // Something like: "np(FooValue.Zero().Length)" - return methodCallExpression.Object; + list.Add(expression!); } + } while (expressionRecognized); - // Something like: "np(MyClasses.FirstOrDefault())" - return methodCallExpression.Arguments.FirstOrDefault(); - } + return list; + } - private static Expression? GetUnaryExpression(UnaryExpression? unaryExpression) + private static Expression? GetMethodCallExpression(MethodCallExpression methodCallExpression) + { + if (methodCallExpression.Object != null) { - return unaryExpression?.Operand; + // Something like: "np(FooValue.Zero().Length)" + return methodCallExpression.Object; } + + // Something like: "np(MyClasses.FirstOrDefault())" + return methodCallExpression.Arguments.FirstOrDefault(); + } + + private static Expression? GetUnaryExpression(UnaryExpression? unaryExpression) + { + return unaryExpression?.Operand; } } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index dad76ebd..cb840f6a 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -12,2202 +12,2209 @@ using System.Reflection; using AnyOfTypes; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +/// +/// ExpressionParser +/// +public class ExpressionParser { + private static readonly string methodOrderBy = nameof(Queryable.OrderBy); + private static readonly string methodOrderByDescending = nameof(Queryable.OrderByDescending); + private static readonly string methodThenBy = nameof(Queryable.ThenBy); + private static readonly string methodThenByDescending = nameof(Queryable.ThenByDescending); + + private readonly ParsingConfig _parsingConfig; + private readonly MethodFinder _methodFinder; + private readonly IKeywordsHelper _keywordsHelper; + private readonly TextParser _textParser; + private readonly NumberParser _numberParser; + private readonly IExpressionHelper _expressionHelper; + private readonly ITypeFinder _typeFinder; + private readonly ITypeConverterFactory _typeConverterFactory; + private readonly Dictionary _internals = new(); + private readonly Dictionary _symbols; + + private IDictionary? _externals; + private ParameterExpression? _it; + private ParameterExpression? _parent; + private ParameterExpression? _root; + private Type? _resultType; + private bool _createParameterCtor; + /// - /// ExpressionParser + /// Gets name for the `it` field. By default this is set to the KeyWord value "it". /// - public class ExpressionParser - { - private static readonly string methodOrderBy = nameof(Queryable.OrderBy); - private static readonly string methodOrderByDescending = nameof(Queryable.OrderByDescending); - private static readonly string methodThenBy = nameof(Queryable.ThenBy); - private static readonly string methodThenByDescending = nameof(Queryable.ThenByDescending); + public string ItName { get; private set; } = KeywordsHelper.KEYWORD_IT; - private readonly ParsingConfig _parsingConfig; - private readonly MethodFinder _methodFinder; - private readonly IKeywordsHelper _keywordsHelper; - private readonly TextParser _textParser; - private readonly NumberParser _numberParser; - private readonly IExpressionHelper _expressionHelper; - private readonly ITypeFinder _typeFinder; - private readonly ITypeConverterFactory _typeConverterFactory; - private readonly Dictionary _internals = new(); - private readonly Dictionary _symbols; + /// + /// There was a problem when an expression contained multiple lambdas where + /// the ItName was not cleared and freed for the next lambda. This variable + /// stores the ItName of the last parsed lambda. + /// Not used internally by ExpressionParser, but used to preserve compatiblity of parsingConfig.RenameParameterExpression + /// which was designed to only work with mono-lambda expressions. + /// + public string LastLambdaItName { get; private set; } = KeywordsHelper.KEYWORD_IT; - private IDictionary? _externals; - private ParameterExpression? _it; - private ParameterExpression? _parent; - private ParameterExpression? _root; - private Type? _resultType; - private bool _createParameterCtor; + /// + /// Initializes a new instance of the class. + /// + /// The parameters. + /// The expression. + /// The values. + /// The parsing configuration. + public ExpressionParser(ParameterExpression[]? parameters, string expression, object?[]? values, ParsingConfig? parsingConfig) + { + Check.NotEmpty(expression, nameof(expression)); - /// - /// Gets name for the `it` field. By default this is set to the KeyWord value "it". - /// - public string ItName { get; private set; } = KeywordsHelper.KEYWORD_IT; + _symbols = new Dictionary(parsingConfig is { IsCaseSensitive: true } ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); + _parsingConfig = parsingConfig ?? ParsingConfig.Default; - /// - /// There was a problem when an expression contained multiple lambdas where - /// the ItName was not cleared and freed for the next lambda. This variable - /// stores the ItName of the last parsed lambda. - /// Not used internally by ExpressionParser, but used to preserve compatiblity of parsingConfig.RenameParameterExpression - /// which was designed to only work with mono-lambda expressions. - /// - public string LastLambdaItName { get; private set; } = KeywordsHelper.KEYWORD_IT; + _keywordsHelper = new KeywordsHelper(_parsingConfig); + _textParser = new TextParser(_parsingConfig, expression); + _numberParser = new NumberParser(parsingConfig); + _methodFinder = new MethodFinder(_parsingConfig); + _expressionHelper = new ExpressionHelper(_parsingConfig); + _typeFinder = new TypeFinder(_parsingConfig, _keywordsHelper); + _typeConverterFactory = new TypeConverterFactory(_parsingConfig); - /// - /// Initializes a new instance of the class. - /// - /// The parameters. - /// The expression. - /// The values. - /// The parsing configuration. - public ExpressionParser(ParameterExpression[]? parameters, string expression, object?[]? values, ParsingConfig? parsingConfig) + if (parameters != null) { - Check.NotEmpty(expression, nameof(expression)); + ProcessParameters(parameters); + } - _symbols = new Dictionary(parsingConfig is { IsCaseSensitive: true } ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); - _parsingConfig = parsingConfig ?? ParsingConfig.Default; + if (values != null) + { + ProcessValues(values); + } + } - _keywordsHelper = new KeywordsHelper(_parsingConfig); - _textParser = new TextParser(_parsingConfig, expression); - _numberParser = new NumberParser(parsingConfig); - _methodFinder = new MethodFinder(_parsingConfig); - _expressionHelper = new ExpressionHelper(_parsingConfig); - _typeFinder = new TypeFinder(_parsingConfig, _keywordsHelper); - _typeConverterFactory = new TypeConverterFactory(_parsingConfig); + private void ProcessParameters(ParameterExpression[] parameters) + { + foreach (ParameterExpression pe in parameters.Where(p => !string.IsNullOrEmpty(p.Name))) + { + AddSymbol(pe.Name, pe); + } - if (parameters != null) - { - ProcessParameters(parameters); - } + // If there is only 1 ParameterExpression, do also allow access using 'it' + if (parameters.Length == 1) + { + _parent = _it; + _it = parameters[0]; - if (values != null) + if (_root == null) { - ProcessValues(values); + _root = _it; } } + } - private void ProcessParameters(ParameterExpression[] parameters) + private void ProcessValues(object?[] values) + { + for (int i = 0; i < values.Length; i++) { - foreach (ParameterExpression pe in parameters.Where(p => !string.IsNullOrEmpty(p.Name))) - { - AddSymbol(pe.Name, pe); - } + object? value = values[i]; + IDictionary? externals; - // If there is only 1 ParameterExpression, do also allow access using 'it' - if (parameters.Length == 1) + if (i == values.Length - 1 && (externals = value as IDictionary) != null) { - _parent = _it; - _it = parameters[0]; - - if (_root == null) - { - _root = _it; - } + _externals = externals; } - } - - private void ProcessValues(object?[] values) - { - for (int i = 0; i < values.Length; i++) + else { - object? value = values[i]; - IDictionary? externals; - - if (i == values.Length - 1 && (externals = value as IDictionary) != null) - { - _externals = externals; - } - else - { - AddSymbol("@" + i.ToString(CultureInfo.InvariantCulture), value); - } + AddSymbol("@" + i.ToString(CultureInfo.InvariantCulture), value); } } + } - private void AddSymbol(string name, object? value) + private void AddSymbol(string name, object? value) + { + if (_symbols.ContainsKey(name)) { - if (_symbols.ContainsKey(name)) - { - throw ParseError(Res.DuplicateIdentifier, name); - } - - _symbols.Add(name, value); + throw ParseError(Res.DuplicateIdentifier, name); } - /// - /// Uses the TextParser to parse the string into the specified result type. - /// - /// Type of the result. - /// if set to true [create parameter ctor]. - /// Expression - public Expression Parse(Type? resultType, bool createParameterCtor = true) - { - _resultType = resultType; - _createParameterCtor = createParameterCtor; + _symbols.Add(name, value); + } - int exprPos = _textParser.CurrentToken.Pos; - Expression? expr = ParseConditionalOperator(); + /// + /// Uses the TextParser to parse the string into the specified result type. + /// + /// Type of the result. + /// if set to true [create parameter ctor]. + /// Expression + public Expression Parse(Type? resultType, bool createParameterCtor = true) + { + _resultType = resultType; + _createParameterCtor = createParameterCtor; - if (resultType != null) + int exprPos = _textParser.CurrentToken.Pos; + Expression? expr = ParseConditionalOperator(); + + if (resultType != null) + { + if ((expr = _parsingConfig.ExpressionPromoter.Promote(expr, resultType, true, false)) == null) { - if ((expr = _parsingConfig.ExpressionPromoter.Promote(expr, resultType, true, false)) == null) - { - throw ParseError(exprPos, Res.ExpressionTypeMismatch, TypeHelper.GetTypeName(resultType)); - } + throw ParseError(exprPos, Res.ExpressionTypeMismatch, TypeHelper.GetTypeName(resultType)); } + } - _textParser.ValidateToken(TokenId.End, Res.SyntaxError); + _textParser.ValidateToken(TokenId.End, Res.SyntaxError); - return expr; - } + return expr; + } #pragma warning disable 0219 - internal IList ParseOrdering(bool forceThenBy = false) + internal IList ParseOrdering(bool forceThenBy = false) + { + var orderings = new List(); + while (true) { - var orderings = new List(); - while (true) + Expression expr = ParseConditionalOperator(); + bool ascending = true; + if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) { - Expression expr = ParseConditionalOperator(); - bool ascending = true; - if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) - { - _textParser.NextToken(); - } - else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) - { - _textParser.NextToken(); - ascending = false; - } - - string methodName; - if (forceThenBy || orderings.Count > 0) - { - methodName = ascending ? methodThenBy : methodThenByDescending; - } - else - { - methodName = ascending ? methodOrderBy : methodOrderByDescending; - } + _textParser.NextToken(); + } + else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) + { + _textParser.NextToken(); + ascending = false; + } - orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending, MethodName = methodName }); + string methodName; + if (forceThenBy || orderings.Count > 0) + { + methodName = ascending ? methodThenBy : methodThenByDescending; + } + else + { + methodName = ascending ? methodOrderBy : methodOrderByDescending; + } - if (_textParser.CurrentToken.Id != TokenId.Comma) - { - break; - } + orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending, MethodName = methodName }); - _textParser.NextToken(); + if (_textParser.CurrentToken.Id != TokenId.Comma) + { + break; } - _textParser.ValidateToken(TokenId.End, Res.SyntaxError); - return orderings; + _textParser.NextToken(); } + + _textParser.ValidateToken(TokenId.End, Res.SyntaxError); + return orderings; + } #pragma warning restore 0219 - // ?: operator - private Expression ParseConditionalOperator() + // ?: operator + private Expression ParseConditionalOperator() + { + int errorPos = _textParser.CurrentToken.Pos; + Expression expr = ParseNullCoalescingOperator(); + if (_textParser.CurrentToken.Id == TokenId.Question) { - int errorPos = _textParser.CurrentToken.Pos; - Expression expr = ParseNullCoalescingOperator(); - if (_textParser.CurrentToken.Id == TokenId.Question) - { - _textParser.NextToken(); - Expression expr1 = ParseConditionalOperator(); - _textParser.ValidateToken(TokenId.Colon, Res.ColonExpected); - _textParser.NextToken(); - Expression expr2 = ParseConditionalOperator(); - expr = GenerateConditional(expr, expr1, expr2, false, errorPos); - } - return expr; + _textParser.NextToken(); + Expression expr1 = ParseConditionalOperator(); + _textParser.ValidateToken(TokenId.Colon, Res.ColonExpected); + _textParser.NextToken(); + Expression expr2 = ParseConditionalOperator(); + expr = GenerateConditional(expr, expr1, expr2, false, errorPos); } + return expr; + } - // ?? (null-coalescing) operator - private Expression ParseNullCoalescingOperator() + // ?? (null-coalescing) operator + private Expression ParseNullCoalescingOperator() + { + Expression expr = ParseLambdaOperator(); + if (_textParser.CurrentToken.Id == TokenId.NullCoalescing) { - Expression expr = ParseLambdaOperator(); - if (_textParser.CurrentToken.Id == TokenId.NullCoalescing) - { - _textParser.NextToken(); - Expression right = ParseConditionalOperator(); - expr = Expression.Coalesce(expr, right); - } - return expr; + _textParser.NextToken(); + Expression right = ParseConditionalOperator(); + expr = Expression.Coalesce(expr, right); } + return expr; + } - // => operator - Added Support for projection operator - private Expression ParseLambdaOperator() + // => operator - Added Support for projection operator + private Expression ParseLambdaOperator() + { + Expression expr = ParseOrOperator(); + if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == expr.Type) { - Expression expr = ParseOrOperator(); - if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == expr.Type) + _textParser.NextToken(); + if (_textParser.CurrentToken.Id == TokenId.Identifier || _textParser.CurrentToken.Id == TokenId.OpenParen) { - _textParser.NextToken(); - if (_textParser.CurrentToken.Id == TokenId.Identifier || _textParser.CurrentToken.Id == TokenId.OpenParen) - { - var right = ParseConditionalOperator(); - return Expression.Lambda(right, new[] { (ParameterExpression)expr }); - } - _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); + var right = ParseConditionalOperator(); + return Expression.Lambda(right, new[] { (ParameterExpression)expr }); } - return expr; + _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); } + return expr; + } - // Or operator - // - || - // - Or - // - OrElse - private Expression ParseOrOperator() + // Or operator + // - || + // - Or + // - OrElse + private Expression ParseOrOperator() + { + Expression left = ParseAndOperator(); + while (_textParser.CurrentToken.Id == TokenId.DoubleBar) { - Expression left = ParseAndOperator(); - while (_textParser.CurrentToken.Id == TokenId.DoubleBar) - { - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - Expression right = ParseAndOperator(); - CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - left = Expression.OrElse(left, right); - } - return left; + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseAndOperator(); + CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = Expression.OrElse(left, right); } + return left; + } - // And operator - // - && - // - And - // - AndAlso - private Expression ParseAndOperator() + // And operator + // - && + // - And + // - AndAlso + private Expression ParseAndOperator() + { + Expression left = ParseIn(); + while (_textParser.CurrentToken.Id == TokenId.DoubleAmpersand) { - Expression left = ParseIn(); - while (_textParser.CurrentToken.Id == TokenId.DoubleAmpersand) - { - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - Expression right = ParseIn(); - CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - left = Expression.AndAlso(left, right); - } - return left; + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseIn(); + CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = Expression.AndAlso(left, right); } + return left; + } + + // in operator for literals - example: "x in (1,2,3,4)" + // in operator to mimic contains - example: "x in @0", compare to @0.Contains(x) + // Adapted from ticket submitted by github user mlewis9548 + private Expression ParseIn() + { + Expression left = ParseLogicalAndOrOperator(); + Expression accumulate = left; - // in operator for literals - example: "x in (1,2,3,4)" - // in operator to mimic contains - example: "x in @0", compare to @0.Contains(x) - // Adapted from ticket submitted by github user mlewis9548 - private Expression ParseIn() + while (TokenIdentifierIs("in")) { - Expression left = ParseLogicalAndOrOperator(); - Expression accumulate = left; + var op = _textParser.CurrentToken; - while (TokenIdentifierIs("in")) + _textParser.NextToken(); + if (_textParser.CurrentToken.Id == TokenId.OpenParen) // literals (or other inline list) { - var op = _textParser.CurrentToken; - - _textParser.NextToken(); - if (_textParser.CurrentToken.Id == TokenId.OpenParen) // literals (or other inline list) + while (_textParser.CurrentToken.Id != TokenId.CloseParen) { - while (_textParser.CurrentToken.Id != TokenId.CloseParen) - { - _textParser.NextToken(); - - // we need to parse unary expressions because otherwise 'in' clause will fail in use cases like 'in (-1, -1)' or 'in (!true)' - Expression right = ParseUnary(); - - // if the identifier is an Enum, try to convert the right-side also to an Enum. - if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression constantExpression) - { - right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpression); - } - - // else, check for direct type match - else if (left.Type != right.Type) - { - CheckAndPromoteOperands(typeof(IEqualitySignatures), TokenId.DoubleEqual, "==", ref left, ref right, op.Pos); - } + _textParser.NextToken(); - if (accumulate.Type != typeof(bool)) - { - accumulate = _expressionHelper.GenerateEqual(left, right); - } - else - { - accumulate = Expression.OrElse(accumulate, _expressionHelper.GenerateEqual(left, right)); - } + // we need to parse unary expressions because otherwise 'in' clause will fail in use cases like 'in (-1, -1)' or 'in (!true)' + Expression right = ParseUnary(); - if (_textParser.CurrentToken.Id == TokenId.End) - { - throw ParseError(op.Pos, Res.CloseParenOrCommaExpected); - } + // if the identifier is an Enum, try to convert the right-side also to an Enum. + if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression constantExpression) + { + right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpression); } - // Since this started with an open paren, make sure to move off the close - _textParser.NextToken(); - } - else if (_textParser.CurrentToken.Id == TokenId.Identifier) // a single argument - { - Expression right = ParsePrimary(); - - if (!typeof(IEnumerable).IsAssignableFrom(right.Type)) + // else, check for direct type match + else if (left.Type != right.Type) { - throw ParseError(_textParser.CurrentToken.Pos, Res.IdentifierImplementingInterfaceExpected, typeof(IEnumerable)); + CheckAndPromoteOperands(typeof(IEqualitySignatures), TokenId.DoubleEqual, "==", ref left, ref right, op.Pos); } - var args = new[] { left }; - - Expression? nullExpressionReference = null; - if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out var containsSignature) != 1) + if (accumulate.Type != typeof(bool)) { - throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray())); + accumulate = _expressionHelper.GenerateEqual(left, right); + } + else + { + accumulate = Expression.OrElse(accumulate, _expressionHelper.GenerateEqual(left, right)); } - var typeArgs = new[] { left.Type }; - - args = new[] { right, left }; - - accumulate = Expression.Call(typeof(Enumerable), containsSignature!.Name, typeArgs, args); - } - else - { - throw ParseError(op.Pos, Res.OpenParenOrIdentifierExpected); + if (_textParser.CurrentToken.Id == TokenId.End) + { + throw ParseError(op.Pos, Res.CloseParenOrCommaExpected); + } } - } - - return accumulate; - } - // &, | bitwise operators - private Expression ParseLogicalAndOrOperator() - { - Expression left = ParseComparisonOperator(); - while (_textParser.CurrentToken.Id == TokenId.Ampersand || _textParser.CurrentToken.Id == TokenId.Bar) - { - Token op = _textParser.CurrentToken; + // Since this started with an open paren, make sure to move off the close _textParser.NextToken(); - Expression right = ParseComparisonOperator(); + } + else if (_textParser.CurrentToken.Id == TokenId.Identifier) // a single argument + { + Expression right = ParsePrimary(); - if (left.Type.GetTypeInfo().IsEnum) + if (!typeof(IEnumerable).IsAssignableFrom(right.Type)) { - left = Expression.Convert(left, Enum.GetUnderlyingType(left.Type)); + throw ParseError(_textParser.CurrentToken.Pos, Res.IdentifierImplementingInterfaceExpected, typeof(IEnumerable)); } - if (right.Type.GetTypeInfo().IsEnum) + var args = new[] { left }; + + Expression? nullExpressionReference = null; + if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out var containsSignature) != 1) { - right = Expression.Convert(right, Enum.GetUnderlyingType(right.Type)); + throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray())); } - switch (op.Id) - { - case TokenId.Ampersand: - if (left.Type == typeof(string) && left.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)left).Value, out var parseValue) && TypeHelper.IsNumericType(right.Type)) - { - left = Expression.Constant(parseValue); - } - else if (right.Type == typeof(string) && right.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)right).Value, out parseValue) && TypeHelper.IsNumericType(left.Type)) - { - right = Expression.Constant(parseValue); - } + var typeArgs = new[] { left.Type }; - // When at least one side of the operator is a string, consider it's a VB-style concatenation operator. - // Doesn't break any other function since logical AND with a string is invalid anyway. - if (left.Type == typeof(string) || right.Type == typeof(string)) - { - left = _expressionHelper.GenerateStringConcat(left, right); - } - else - { - _expressionHelper.ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right); - left = Expression.And(left, right); - } - break; + args = new[] { right, left }; - case TokenId.Bar: - _expressionHelper.ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right); - left = Expression.Or(left, right); - break; - } + accumulate = Expression.Call(typeof(Enumerable), containsSignature!.Name, typeArgs, args); + } + else + { + throw ParseError(op.Pos, Res.OpenParenOrIdentifierExpected); } - return left; } - // =, ==, !=, <>, >, >=, <, <= operators - private Expression ParseComparisonOperator() + return accumulate; + } + + // &, | bitwise operators + private Expression ParseLogicalAndOrOperator() + { + Expression left = ParseComparisonOperator(); + while (_textParser.CurrentToken.Id == TokenId.Ampersand || _textParser.CurrentToken.Id == TokenId.Bar) { - Expression left = ParseShiftOperator(); - while (_textParser.CurrentToken.Id == TokenId.Equal || _textParser.CurrentToken.Id == TokenId.DoubleEqual || - _textParser.CurrentToken.Id == TokenId.ExclamationEqual || _textParser.CurrentToken.Id == TokenId.LessGreater || - _textParser.CurrentToken.Id == TokenId.GreaterThan || _textParser.CurrentToken.Id == TokenId.GreaterThanEqual || - _textParser.CurrentToken.Id == TokenId.LessThan || _textParser.CurrentToken.Id == TokenId.LessThanEqual) + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseComparisonOperator(); + + if (left.Type.GetTypeInfo().IsEnum) { - ConstantExpression? constantExpr; - TypeConverter typeConverter; - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - Expression right = ParseShiftOperator(); - bool isEquality = op.Id == TokenId.Equal || op.Id == TokenId.DoubleEqual || op.Id == TokenId.ExclamationEqual || op.Id == TokenId.LessGreater; + left = Expression.Convert(left, Enum.GetUnderlyingType(left.Type)); + } - if (isEquality && (!left.Type.GetTypeInfo().IsValueType && !right.Type.GetTypeInfo().IsValueType || left.Type == typeof(Guid) && right.Type == typeof(Guid))) - { - // If left or right is NullLiteral, just continue. Else check if the types differ. - if (!(Constants.IsNull(left) || Constants.IsNull(right)) && left.Type != right.Type) + if (right.Type.GetTypeInfo().IsEnum) + { + right = Expression.Convert(right, Enum.GetUnderlyingType(right.Type)); + } + + switch (op.Id) + { + case TokenId.Ampersand: + if (left.Type == typeof(string) && left.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)left).Value, out var parseValue) && TypeHelper.IsNumericType(right.Type)) { - if (left.Type.IsAssignableFrom(right.Type) || HasImplicitConversion(right.Type, left.Type)) - { - right = Expression.Convert(right, left.Type); - } - else if (right.Type.IsAssignableFrom(left.Type) || HasImplicitConversion(left.Type, right.Type)) - { - left = Expression.Convert(left, right.Type); - } - else - { - throw IncompatibleOperandsError(op.Text, left, right, op.Pos); - } + left = Expression.Constant(parseValue); } - } - else if (TypeHelper.IsEnumType(left.Type) || TypeHelper.IsEnumType(right.Type)) + else if (right.Type == typeof(string) && right.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)right).Value, out parseValue) && TypeHelper.IsNumericType(left.Type)) + { + right = Expression.Constant(parseValue); + } + + // When at least one side of the operator is a string, consider it's a VB-style concatenation operator. + // Doesn't break any other function since logical AND with a string is invalid anyway. + if (left.Type == typeof(string) || right.Type == typeof(string)) + { + left = _expressionHelper.GenerateStringConcat(left, right); + } + else + { + _expressionHelper.ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right); + left = Expression.And(left, right); + } + break; + + case TokenId.Bar: + _expressionHelper.ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right); + left = Expression.Or(left, right); + break; + } + } + return left; + } + + // =, ==, !=, <>, >, >=, <, <= operators + private Expression ParseComparisonOperator() + { + Expression left = ParseShiftOperator(); + while (_textParser.CurrentToken.Id == TokenId.Equal || _textParser.CurrentToken.Id == TokenId.DoubleEqual || + _textParser.CurrentToken.Id == TokenId.ExclamationEqual || _textParser.CurrentToken.Id == TokenId.LessGreater || + _textParser.CurrentToken.Id == TokenId.GreaterThan || _textParser.CurrentToken.Id == TokenId.GreaterThanEqual || + _textParser.CurrentToken.Id == TokenId.LessThan || _textParser.CurrentToken.Id == TokenId.LessThanEqual) + { + ConstantExpression? constantExpr; + TypeConverter typeConverter; + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseShiftOperator(); + bool isEquality = op.Id == TokenId.Equal || op.Id == TokenId.DoubleEqual || op.Id == TokenId.ExclamationEqual || op.Id == TokenId.LessGreater; + + if (isEquality && (!left.Type.GetTypeInfo().IsValueType && !right.Type.GetTypeInfo().IsValueType || left.Type == typeof(Guid) && right.Type == typeof(Guid))) + { + // If left or right is NullLiteral, just continue. Else check if the types differ. + if (!(Constants.IsNull(left) || Constants.IsNull(right)) && left.Type != right.Type) { - if (left.Type != right.Type) + if (left.Type.IsAssignableFrom(right.Type) || HasImplicitConversion(right.Type, left.Type)) { - Expression? e; - if ((e = _parsingConfig.ExpressionPromoter.Promote(right, left.Type, true, false)) != null) - { - right = e; - } - else if ((e = _parsingConfig.ExpressionPromoter.Promote(left, right.Type, true, false)) != null) - { - left = e; - } - else if (TypeHelper.IsEnumType(left.Type) && (constantExpr = right as ConstantExpression) != null) - { - right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpr); - } - else if (TypeHelper.IsEnumType(right.Type) && (constantExpr = left as ConstantExpression) != null) - { - left = ParseEnumToConstantExpression(op.Pos, right.Type, constantExpr); - } - else - { - throw IncompatibleOperandsError(op.Text, left, right, op.Pos); - } + right = Expression.Convert(right, left.Type); + } + else if (right.Type.IsAssignableFrom(left.Type) || HasImplicitConversion(left.Type, right.Type)) + { + left = Expression.Convert(left, right.Type); + } + else + { + throw IncompatibleOperandsError(op.Text, left, right, op.Pos); } } - else if ((constantExpr = right as ConstantExpression) != null && constantExpr.Value is string stringValueR && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null) + } + else if (TypeHelper.IsEnumType(left.Type) || TypeHelper.IsEnumType(right.Type)) + { + if (left.Type != right.Type) { - right = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueR), left.Type); + Expression? e; + if ((e = _parsingConfig.ExpressionPromoter.Promote(right, left.Type, true, false)) != null) + { + right = e; + } + else if ((e = _parsingConfig.ExpressionPromoter.Promote(left, right.Type, true, false)) != null) + { + left = e; + } + else if (TypeHelper.IsEnumType(left.Type) && (constantExpr = right as ConstantExpression) != null) + { + right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpr); + } + else if (TypeHelper.IsEnumType(right.Type) && (constantExpr = left as ConstantExpression) != null) + { + left = ParseEnumToConstantExpression(op.Pos, right.Type, constantExpr); + } + else + { + throw IncompatibleOperandsError(op.Text, left, right, op.Pos); + } } - else if ((constantExpr = left as ConstantExpression) != null && constantExpr.Value is string stringValueL && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null) + } + else if ((constantExpr = right as ConstantExpression) != null && constantExpr.Value is string stringValueR && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null) + { + right = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueR), left.Type); + } + else if ((constantExpr = left as ConstantExpression) != null && constantExpr.Value is string stringValueL && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null) + { + left = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueL), right.Type); + } + else if (_expressionHelper.TryUnwrapConstantExpression(right, out var unwrappedStringValueR) && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null) + { + right = Expression.Constant(typeConverter.ConvertFromInvariantString(unwrappedStringValueR), left.Type); + } + else if (_expressionHelper.TryUnwrapConstantExpression(left, out var unwrappedStringValueL) && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null) + { + left = Expression.Constant(typeConverter.ConvertFromInvariantString(unwrappedStringValueL), right.Type); + } + else + { + bool typesAreSameAndImplementCorrectInterface = false; + if (left.Type == right.Type) { - left = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueL), right.Type); + var interfaces = left.Type.GetInterfaces().Where(x => x.GetTypeInfo().IsGenericType); + if (isEquality) + { + typesAreSameAndImplementCorrectInterface = interfaces.Any(x => x.GetGenericTypeDefinition() == typeof(IEquatable<>)); + } + else + { + typesAreSameAndImplementCorrectInterface = interfaces.Any(x => x.GetGenericTypeDefinition() == typeof(IComparable<>)); + } } - else + + if (!typesAreSameAndImplementCorrectInterface) { - bool typesAreSameAndImplementCorrectInterface = false; - if (left.Type == right.Type) + if ((TypeHelper.IsClass(left.Type) || TypeHelper.IsStruct(left.Type)) && right is ConstantExpression) { - var interfaces = left.Type.GetInterfaces().Where(x => x.GetTypeInfo().IsGenericType); - if (isEquality) + if (HasImplicitConversion(left.Type, right.Type)) { - typesAreSameAndImplementCorrectInterface = interfaces.Any(x => x.GetGenericTypeDefinition() == typeof(IEquatable<>)); + left = Expression.Convert(left, right.Type); } - else + else if (HasImplicitConversion(right.Type, left.Type)) { - typesAreSameAndImplementCorrectInterface = interfaces.Any(x => x.GetGenericTypeDefinition() == typeof(IComparable<>)); + right = Expression.Convert(right, left.Type); } } - - if (!typesAreSameAndImplementCorrectInterface) + else if ((TypeHelper.IsClass(right.Type) || TypeHelper.IsStruct(right.Type)) && left is ConstantExpression) { - if ((TypeHelper.IsClass(left.Type) || TypeHelper.IsStruct(left.Type)) && right is ConstantExpression) - { - if (HasImplicitConversion(left.Type, right.Type)) - { - left = Expression.Convert(left, right.Type); - } - else if (HasImplicitConversion(right.Type, left.Type)) - { - right = Expression.Convert(right, left.Type); - } - } - else if ((TypeHelper.IsClass(right.Type) || TypeHelper.IsStruct(right.Type)) && left is ConstantExpression) + if (HasImplicitConversion(right.Type, left.Type)) { - if (HasImplicitConversion(right.Type, left.Type)) - { - right = Expression.Convert(right, left.Type); - } - else if (HasImplicitConversion(left.Type, right.Type)) - { - left = Expression.Convert(left, right.Type); - } + right = Expression.Convert(right, left.Type); } - else + else if (HasImplicitConversion(left.Type, right.Type)) { - CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = Expression.Convert(left, right.Type); } } - } - - switch (op.Id) - { - case TokenId.Equal: - case TokenId.DoubleEqual: - left = _expressionHelper.GenerateEqual(left, right); - break; - case TokenId.ExclamationEqual: - case TokenId.LessGreater: - left = _expressionHelper.GenerateNotEqual(left, right); - break; - case TokenId.GreaterThan: - left = _expressionHelper.GenerateGreaterThan(left, right); - break; - case TokenId.GreaterThanEqual: - left = _expressionHelper.GenerateGreaterThanEqual(left, right); - break; - case TokenId.LessThan: - left = _expressionHelper.GenerateLessThan(left, right); - break; - case TokenId.LessThanEqual: - left = _expressionHelper.GenerateLessThanEqual(left, right); - break; + else + { + CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + } } } - return left; + switch (op.Id) + { + case TokenId.Equal: + case TokenId.DoubleEqual: + left = _expressionHelper.GenerateEqual(left, right); + break; + case TokenId.ExclamationEqual: + case TokenId.LessGreater: + left = _expressionHelper.GenerateNotEqual(left, right); + break; + case TokenId.GreaterThan: + left = _expressionHelper.GenerateGreaterThan(left, right); + break; + case TokenId.GreaterThanEqual: + left = _expressionHelper.GenerateGreaterThanEqual(left, right); + break; + case TokenId.LessThan: + left = _expressionHelper.GenerateLessThan(left, right); + break; + case TokenId.LessThanEqual: + left = _expressionHelper.GenerateLessThanEqual(left, right); + break; + } } - private bool HasImplicitConversion(Type baseType, Type targetType) + return left; + } + + private bool HasImplicitConversion(Type baseType, Type targetType) + { + var baseTypeHasConversion = baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) + .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); + + if (baseTypeHasConversion) { - var baseTypeHasConversion = baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) - .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); + return true; + } - if (baseTypeHasConversion) + return targetType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) + .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); + } + + private ConstantExpression ParseEnumToConstantExpression(int pos, Type leftType, ConstantExpression constantExpr) + { + return Expression.Constant(ParseConstantExpressionToEnum(pos, leftType, constantExpr), leftType); + } + + private object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExpression constantExpr) + { + try + { + if (constantExpr.Value is string stringValue) { - return true; + return Enum.Parse(TypeHelper.GetNonNullableType(leftType), stringValue, true); } - - return targetType.GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) - .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); } - - private ConstantExpression ParseEnumToConstantExpression(int pos, Type leftType, ConstantExpression constantExpr) + catch { - return Expression.Constant(ParseConstantExpressionToEnum(pos, leftType, constantExpr), leftType); + throw ParseError(pos, Res.ExpressionTypeMismatch, leftType); } - private object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExpression constantExpr) + try { - try - { - if (constantExpr.Value is string stringValue) - { - return Enum.Parse(TypeHelper.GetNonNullableType(leftType), stringValue, true); - } - } - catch - { - throw ParseError(pos, Res.ExpressionTypeMismatch, leftType); - } + return Enum.ToObject(TypeHelper.GetNonNullableType(leftType), constantExpr.Value); + } + catch + { + throw ParseError(pos, Res.ExpressionTypeMismatch, leftType); + } + } - try - { - return Enum.ToObject(TypeHelper.GetNonNullableType(leftType), constantExpr.Value); - } - catch + // <<, >> operators + private Expression ParseShiftOperator() + { + Expression left = ParseAdditive(); + while (_textParser.CurrentToken.Id == TokenId.DoubleLessThan || _textParser.CurrentToken.Id == TokenId.DoubleGreaterThan) + { + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseAdditive(); + switch (op.Id) { - throw ParseError(pos, Res.ExpressionTypeMismatch, leftType); + case TokenId.DoubleLessThan: + CheckAndPromoteOperands(typeof(IShiftSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = Expression.LeftShift(left, right); + break; + case TokenId.DoubleGreaterThan: + CheckAndPromoteOperands(typeof(IShiftSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = Expression.RightShift(left, right); + break; } } + return left; + } - // <<, >> operators - private Expression ParseShiftOperator() + // +, - operators + private Expression ParseAdditive() + { + Expression left = ParseMultiplicative(); + while (_textParser.CurrentToken.Id == TokenId.Plus || _textParser.CurrentToken.Id == TokenId.Minus) { - Expression left = ParseAdditive(); - while (_textParser.CurrentToken.Id == TokenId.DoubleLessThan || _textParser.CurrentToken.Id == TokenId.DoubleGreaterThan) + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseMultiplicative(); + switch (op.Id) { - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - Expression right = ParseAdditive(); - switch (op.Id) - { - case TokenId.DoubleLessThan: - CheckAndPromoteOperands(typeof(IShiftSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - left = Expression.LeftShift(left, right); - break; - case TokenId.DoubleGreaterThan: - CheckAndPromoteOperands(typeof(IShiftSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - left = Expression.RightShift(left, right); - break; - } + case TokenId.Plus: + if (left.Type == typeof(string) || right.Type == typeof(string)) + { + left = _expressionHelper.GenerateStringConcat(left, right); + } + else + { + CheckAndPromoteOperands(typeof(IAddSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = _expressionHelper.GenerateAdd(left, right); + } + break; + case TokenId.Minus: + CheckAndPromoteOperands(typeof(ISubtractSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + left = _expressionHelper.GenerateSubtract(left, right); + break; } - return left; } + return left; + } - // +, - operators - private Expression ParseAdditive() + // *, /, %, mod operators + private Expression ParseMultiplicative() + { + Expression left = ParseUnary(); + while (_textParser.CurrentToken.Id == TokenId.Asterisk || _textParser.CurrentToken.Id == TokenId.Slash || + _textParser.CurrentToken.Id == TokenId.Percent || TokenIdentifierIs("mod")) { - Expression left = ParseMultiplicative(); - while (_textParser.CurrentToken.Id == TokenId.Plus || _textParser.CurrentToken.Id == TokenId.Minus) + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + Expression right = ParseUnary(); + CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + switch (op.Id) { - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - Expression right = ParseMultiplicative(); - switch (op.Id) - { - case TokenId.Plus: - if (left.Type == typeof(string) || right.Type == typeof(string)) - { - left = _expressionHelper.GenerateStringConcat(left, right); - } - else - { - CheckAndPromoteOperands(typeof(IAddSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - left = _expressionHelper.GenerateAdd(left, right); - } - break; - case TokenId.Minus: - CheckAndPromoteOperands(typeof(ISubtractSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - left = _expressionHelper.GenerateSubtract(left, right); - break; - } + case TokenId.Asterisk: + left = Expression.Multiply(left, right); + break; + case TokenId.Slash: + left = Expression.Divide(left, right); + break; + case TokenId.Percent: + case TokenId.Identifier: + left = Expression.Modulo(left, right); + break; } - return left; } + return left; + } - // *, /, %, mod operators - private Expression ParseMultiplicative() + // -, !, not unary operators + private Expression ParseUnary() + { + if (_textParser.CurrentToken.Id == TokenId.Minus || _textParser.CurrentToken.Id == TokenId.Exclamation || TokenIdentifierIs("not")) { - Expression left = ParseUnary(); - while (_textParser.CurrentToken.Id == TokenId.Asterisk || _textParser.CurrentToken.Id == TokenId.Slash || - _textParser.CurrentToken.Id == TokenId.Percent || TokenIdentifierIs("mod")) + Token op = _textParser.CurrentToken; + _textParser.NextToken(); + if (op.Id == TokenId.Minus && (_textParser.CurrentToken.Id == TokenId.IntegerLiteral || _textParser.CurrentToken.Id == TokenId.RealLiteral)) { - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - Expression right = ParseUnary(); - CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.Id, op.Text, ref left, ref right, op.Pos); - switch (op.Id) - { - case TokenId.Asterisk: - left = Expression.Multiply(left, right); - break; - case TokenId.Slash: - left = Expression.Divide(left, right); - break; - case TokenId.Percent: - case TokenId.Identifier: - left = Expression.Modulo(left, right); - break; - } + _textParser.CurrentToken.Text = "-" + _textParser.CurrentToken.Text; + _textParser.CurrentToken.Pos = op.Pos; + return ParsePrimary(); } - return left; - } - // -, !, not unary operators - private Expression ParseUnary() - { - if (_textParser.CurrentToken.Id == TokenId.Minus || _textParser.CurrentToken.Id == TokenId.Exclamation || TokenIdentifierIs("not")) + Expression expr = ParseUnary(); + if (op.Id == TokenId.Minus) { - Token op = _textParser.CurrentToken; - _textParser.NextToken(); - if (op.Id == TokenId.Minus && (_textParser.CurrentToken.Id == TokenId.IntegerLiteral || _textParser.CurrentToken.Id == TokenId.RealLiteral)) - { - _textParser.CurrentToken.Text = "-" + _textParser.CurrentToken.Text; - _textParser.CurrentToken.Pos = op.Pos; - return ParsePrimary(); - } - - Expression expr = ParseUnary(); - if (op.Id == TokenId.Minus) - { - CheckAndPromoteOperand(typeof(INegationSignatures), op.Text, ref expr, op.Pos); - expr = Expression.Negate(expr); - } - else - { - CheckAndPromoteOperand(typeof(INotSignatures), op.Text, ref expr, op.Pos); - expr = Expression.Not(expr); - } - - return expr; + CheckAndPromoteOperand(typeof(INegationSignatures), op.Text, ref expr, op.Pos); + expr = Expression.Negate(expr); + } + else + { + CheckAndPromoteOperand(typeof(INotSignatures), op.Text, ref expr, op.Pos); + expr = Expression.Not(expr); } - return ParsePrimary(); + return expr; } - private Expression ParsePrimary() - { - var expr = ParsePrimaryStart(); - _expressionHelper.WrapConstantExpression(ref expr); + return ParsePrimary(); + } - while (true) + private Expression ParsePrimary() + { + var expr = ParsePrimaryStart(); + _expressionHelper.WrapConstantExpression(ref expr); + + while (true) + { + if (_textParser.CurrentToken.Id == TokenId.Dot) { - if (_textParser.CurrentToken.Id == TokenId.Dot) - { - _textParser.NextToken(); - expr = ParseMemberAccess(null, expr); - } - else if (_textParser.CurrentToken.Id == TokenId.NullPropagation) - { - throw new NotSupportedException("An expression tree lambda may not contain a null propagating operator. Use the 'np()' or 'np(...)' (null-propagation) function instead."); - } - else if (_textParser.CurrentToken.Id == TokenId.OpenBracket) - { - expr = ParseElementAccess(expr); - } - else - { - break; - } + _textParser.NextToken(); + expr = ParseMemberAccess(null, expr); + } + else if (_textParser.CurrentToken.Id == TokenId.NullPropagation) + { + throw new NotSupportedException("An expression tree lambda may not contain a null propagating operator. Use the 'np()' or 'np(...)' (null-propagation) function instead."); + } + else if (_textParser.CurrentToken.Id == TokenId.OpenBracket) + { + expr = ParseElementAccess(expr); + } + else + { + break; } - - return expr; } - private Expression ParsePrimaryStart() + return expr; + } + + private Expression ParsePrimaryStart() + { + switch (_textParser.CurrentToken.Id) { - switch (_textParser.CurrentToken.Id) - { - case TokenId.Identifier: - return ParseIdentifier(); + case TokenId.Identifier: + return ParseIdentifier(); - case TokenId.StringLiteral: - var expressionOrType = ParseStringLiteral(false); - return expressionOrType.IsFirst ? expressionOrType.First : ParseTypeAccess(expressionOrType.Second, false); + case TokenId.StringLiteral: + var expressionOrType = ParseStringLiteral(false); + return expressionOrType.IsFirst ? expressionOrType.First : ParseTypeAccess(expressionOrType.Second, false); - case TokenId.IntegerLiteral: - return ParseIntegerLiteral(); + case TokenId.IntegerLiteral: + return ParseIntegerLiteral(); - case TokenId.RealLiteral: - return ParseRealLiteral(); + case TokenId.RealLiteral: + return ParseRealLiteral(); - case TokenId.OpenParen: - return ParseParenExpression(); + case TokenId.OpenParen: + return ParseParenExpression(); - default: - throw ParseError(Res.ExpressionExpected); - } + default: + throw ParseError(Res.ExpressionExpected); } + } - private AnyOf ParseStringLiteral(bool forceParseAsString) - { - _textParser.ValidateToken(TokenId.StringLiteral); + private AnyOf ParseStringLiteral(bool forceParseAsString) + { + _textParser.ValidateToken(TokenId.StringLiteral); - var stringValue = StringParser.ParseString(_textParser.CurrentToken.Text); + var stringValue = StringParser.ParseString(_textParser.CurrentToken.Text); - if (_textParser.CurrentToken.Text[0] == '\'') + if (_textParser.CurrentToken.Text[0] == '\'') + { + if (stringValue.Length > 1) { - if (stringValue.Length > 1) - { - throw ParseError(Res.InvalidCharacterLiteral); - } - - _textParser.NextToken(); - return ConstantExpressionHelper.CreateLiteral(stringValue[0], stringValue); + throw ParseError(Res.InvalidCharacterLiteral); } _textParser.NextToken(); + return ConstantExpressionHelper.CreateLiteral(stringValue[0], stringValue); + } - if (_parsingConfig.SupportCastingToFullyQualifiedTypeAsString && !forceParseAsString && stringValue.Length > 2 && stringValue.Contains('.')) + _textParser.NextToken(); + + if (_parsingConfig.SupportCastingToFullyQualifiedTypeAsString && !forceParseAsString && stringValue.Length > 2 && stringValue.Contains('.')) + { + // Try to resolve this string as a type + var type = _typeFinder.FindTypeByName(stringValue, null, false); + if (type is { }) { - // Try to resolve this string as a type - var type = _typeFinder.FindTypeByName(stringValue, null, false); - if (type is { }) - { - return type; - } + return type; } - - return ConstantExpressionHelper.CreateLiteral(stringValue, stringValue); } - private Expression ParseIntegerLiteral() - { - _textParser.ValidateToken(TokenId.IntegerLiteral); + return ConstantExpressionHelper.CreateLiteral(stringValue, stringValue); + } - string text = _textParser.CurrentToken.Text; + private Expression ParseIntegerLiteral() + { + _textParser.ValidateToken(TokenId.IntegerLiteral); - var tokenPosition = _textParser.CurrentToken.Pos; + string text = _textParser.CurrentToken.Text; - var constantExpression = _numberParser.ParseIntegerLiteral(tokenPosition, text); - _textParser.NextToken(); - return constantExpression; - } + var tokenPosition = _textParser.CurrentToken.Pos; - private Expression ParseRealLiteral() - { - _textParser.ValidateToken(TokenId.RealLiteral); + var constantExpression = _numberParser.ParseIntegerLiteral(tokenPosition, text); + _textParser.NextToken(); + return constantExpression; + } - string text = _textParser.CurrentToken.Text; + private Expression ParseRealLiteral() + { + _textParser.ValidateToken(TokenId.RealLiteral); - _textParser.NextToken(); + string text = _textParser.CurrentToken.Text; - return _numberParser.ParseRealLiteral(text, text[text.Length - 1], true); - } + _textParser.NextToken(); - private Expression ParseParenExpression() - { - _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); - _textParser.NextToken(); - Expression e = ParseConditionalOperator(); - _textParser.ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected); - _textParser.NextToken(); - return e; - } + return _numberParser.ParseRealLiteral(text, text[text.Length - 1], true); + } - private Expression ParseIdentifier() - { - _textParser.ValidateToken(TokenId.Identifier); + private Expression ParseParenExpression() + { + _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); + _textParser.NextToken(); + Expression e = ParseConditionalOperator(); + _textParser.ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected); + _textParser.NextToken(); + return e; + } - var isValidKeyWord = _keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out var value); + private Expression ParseIdentifier() + { + _textParser.ValidateToken(TokenId.Identifier); + + var isValidKeyWord = _keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out var value); - var extraCondition = !_parsingConfig.PrioritizePropertyOrFieldOverTheType || - (_parsingConfig.PrioritizePropertyOrFieldOverTheType && !(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null)); + var extraCondition = !_parsingConfig.PrioritizePropertyOrFieldOverTheType || + (_parsingConfig.PrioritizePropertyOrFieldOverTheType && !(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null)); - if (isValidKeyWord && extraCondition) + if (isValidKeyWord && extraCondition) + { + if (value is Type typeValue) { - if (value is Type typeValue) - { - return ParseTypeAccess(typeValue, true); - } + return ParseTypeAccess(typeValue, true); + } - switch (value) - { - case KeywordsHelper.KEYWORD_IT: - case KeywordsHelper.SYMBOL_IT: - return ParseIt(); + switch (value) + { + case KeywordsHelper.KEYWORD_IT: + case KeywordsHelper.SYMBOL_IT: + return ParseIt(); - case KeywordsHelper.KEYWORD_PARENT: - case KeywordsHelper.SYMBOL_PARENT: - return ParseParent(); + case KeywordsHelper.KEYWORD_PARENT: + case KeywordsHelper.SYMBOL_PARENT: + return ParseParent(); - case KeywordsHelper.KEYWORD_ROOT: - case KeywordsHelper.SYMBOL_ROOT: - return ParseRoot(); + case KeywordsHelper.KEYWORD_ROOT: + case KeywordsHelper.SYMBOL_ROOT: + return ParseRoot(); - case KeywordsHelper.FUNCTION_IIF: - return ParseFunctionIif(); + case KeywordsHelper.FUNCTION_IIF: + return ParseFunctionIif(); - case KeywordsHelper.FUNCTION_ISNULL: - return ParseFunctionIsNull(); + case KeywordsHelper.FUNCTION_ISNULL: + return ParseFunctionIsNull(); - case KeywordsHelper.FUNCTION_NEW: - return ParseNew(); + case KeywordsHelper.FUNCTION_NEW: + return ParseNew(); - case KeywordsHelper.FUNCTION_NULLPROPAGATION: - return ParseFunctionNullPropagation(); + case KeywordsHelper.FUNCTION_NULLPROPAGATION: + return ParseFunctionNullPropagation(); - case KeywordsHelper.FUNCTION_IS: - return ParseFunctionIs(); + case KeywordsHelper.FUNCTION_IS: + return ParseFunctionIs(); - case KeywordsHelper.FUNCTION_AS: - return ParseFunctionAs(); + case KeywordsHelper.FUNCTION_AS: + return ParseFunctionAs(); - case KeywordsHelper.FUNCTION_CAST: - return ParseFunctionCast(); - } + case KeywordsHelper.FUNCTION_CAST: + return ParseFunctionCast(); + } - _textParser.NextToken(); + _textParser.NextToken(); - return (Expression)value; - } + return (Expression)value; + } - if (_symbols.TryGetValue(_textParser.CurrentToken.Text, out value) || - _externals != null && _externals.TryGetValue(_textParser.CurrentToken.Text, out value) || - _internals.TryGetValue(_textParser.CurrentToken.Text, out value)) + if (_symbols.TryGetValue(_textParser.CurrentToken.Text, out value) || + _externals != null && _externals.TryGetValue(_textParser.CurrentToken.Text, out value) || + _internals.TryGetValue(_textParser.CurrentToken.Text, out value)) + { + var expr = value as Expression; + if (expr == null) { - var expr = value as Expression; - if (expr == null) - { - expr = Expression.Constant(value); - } - else + expr = Expression.Constant(value); + } + else + { + if (expr is LambdaExpression lambdaExpression) { - if (expr is LambdaExpression lambdaExpression) - { - return ParseLambdaInvocation(lambdaExpression); - } + return ParseLambdaInvocation(lambdaExpression); } - - _textParser.NextToken(); - - return expr; } - if (_it != null) - { - return ParseMemberAccess(null, _it); - } + _textParser.NextToken(); - throw ParseError(Res.UnknownIdentifier, _textParser.CurrentToken.Text); + return expr; } - private Expression ParseIt() + if (_it != null) { - if (_it == null) - { - throw ParseError(Res.NoItInScope); - } - _textParser.NextToken(); - return _it; + return ParseMemberAccess(null, _it); } - private Expression ParseParent() + throw ParseError(Res.UnknownIdentifier, _textParser.CurrentToken.Text); + } + + private Expression ParseIt() + { + if (_it == null) { - if (_parent == null) - { - throw ParseError(Res.NoParentInScope); - } - _textParser.NextToken(); - return _parent; + throw ParseError(Res.NoItInScope); } + _textParser.NextToken(); + return _it; + } - private Expression ParseRoot() + private Expression ParseParent() + { + if (_parent == null) { - if (_root == null) - { - throw ParseError(Res.NoRootInScope); - } - _textParser.NextToken(); - return _root; + throw ParseError(Res.NoParentInScope); } + _textParser.NextToken(); + return _parent; + } - // isnull(a,b) function - private Expression ParseFunctionIsNull() + private Expression ParseRoot() + { + if (_root == null) { - int errorPos = _textParser.CurrentToken.Pos; - _textParser.NextToken(); - Expression[] args = ParseArgumentList(); - if (args.Length != 2) - { - throw ParseError(errorPos, Res.IsNullRequiresTwoArgs); - } - - return Expression.Coalesce(args[0], args[1]); + throw ParseError(Res.NoRootInScope); } + _textParser.NextToken(); + return _root; + } - // iif(test, ifTrue, ifFalse) function - private Expression ParseFunctionIif() + // isnull(a,b) function + private Expression ParseFunctionIsNull() + { + int errorPos = _textParser.CurrentToken.Pos; + _textParser.NextToken(); + Expression[] args = ParseArgumentList(); + if (args.Length != 2) { - int errorPos = _textParser.CurrentToken.Pos; - _textParser.NextToken(); + throw ParseError(errorPos, Res.IsNullRequiresTwoArgs); + } - Expression[] args = ParseArgumentList(); - if (args.Length != 3) - { - throw ParseError(errorPos, Res.IifRequiresThreeArgs); - } + return Expression.Coalesce(args[0], args[1]); + } - return GenerateConditional(args[0], args[1], args[2], false, errorPos); + // iif(test, ifTrue, ifFalse) function + private Expression ParseFunctionIif() + { + int errorPos = _textParser.CurrentToken.Pos; + _textParser.NextToken(); + + Expression[] args = ParseArgumentList(); + if (args.Length != 3) + { + throw ParseError(errorPos, Res.IifRequiresThreeArgs); } - // np(...) function - private Expression ParseFunctionNullPropagation() + return GenerateConditional(args[0], args[1], args[2], false, errorPos); + } + + // np(...) function + private Expression ParseFunctionNullPropagation() + { + int errorPos = _textParser.CurrentToken.Pos; + _textParser.NextToken(); + + Expression[] args = ParseArgumentList(); + + if (args.Length != 1 && args.Length != 2) { - int errorPos = _textParser.CurrentToken.Pos; - _textParser.NextToken(); + throw ParseError(errorPos, Res.NullPropagationRequiresCorrectArgs); + } - Expression[] args = ParseArgumentList(); + if (_expressionHelper.ExpressionQualifiesForNullPropagation(args[0])) + { + bool hasDefaultParameter = args.Length == 2; + Expression expressionIfFalse = hasDefaultParameter ? args[1] : Expression.Constant(null); - if (args.Length != 1 && args.Length != 2) + if (_expressionHelper.TryGenerateAndAlsoNotNullExpression(args[0], true, out Expression generatedExpression)) { - throw ParseError(errorPos, Res.NullPropagationRequiresCorrectArgs); + return GenerateConditional(generatedExpression, args[0], expressionIfFalse, true, errorPos); } - if (_expressionHelper.ExpressionQualifiesForNullPropagation(args[0])) - { - bool hasDefaultParameter = args.Length == 2; - Expression expressionIfFalse = hasDefaultParameter ? args[1] : Expression.Constant(null); + return args[0]; + } - if (_expressionHelper.TryGenerateAndAlsoNotNullExpression(args[0], true, out Expression generatedExpression)) - { - return GenerateConditional(generatedExpression, args[0], expressionIfFalse, true, errorPos); - } + throw ParseError(errorPos, Res.NullPropagationRequiresValidExpression); + } - return args[0]; - } + // Is(...) function + private Expression ParseFunctionIs() + { + int errorPos = _textParser.CurrentToken.Pos; + string functionName = _textParser.CurrentToken.Text; + _textParser.NextToken(); + + Expression[] args = ParseArgumentList(); - throw ParseError(errorPos, Res.NullPropagationRequiresValidExpression); + if (args.Length != 1 && args.Length != 2) + { + throw ParseError(errorPos, Res.FunctionRequiresOneOrTwoArgs, functionName); } - // Is(...) function - private Expression ParseFunctionIs() + Expression typeArgument; + Expression it; + if (args.Length == 1) { - int errorPos = _textParser.CurrentToken.Pos; - string functionName = _textParser.CurrentToken.Text; - _textParser.NextToken(); + typeArgument = args[0]; + it = _it!; + } + else + { + typeArgument = args[1]; + it = args[0]; + } - Expression[] args = ParseArgumentList(); + return Expression.TypeIs(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); + } - if (args.Length != 1 && args.Length != 2) - { - throw ParseError(errorPos, Res.FunctionRequiresOneOrTwoArgs, functionName); - } + // As(...) function + private Expression ParseFunctionAs() + { + int errorPos = _textParser.CurrentToken.Pos; + string functionName = _textParser.CurrentToken.Text; + _textParser.NextToken(); - Expression typeArgument; - Expression it; - if (args.Length == 1) - { - typeArgument = args[0]; - it = _it!; - } - else - { - typeArgument = args[1]; - it = args[0]; - } + Expression[] args = ParseArgumentList(); - return Expression.TypeIs(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); + if (args.Length != 1 && args.Length != 2) + { + throw ParseError(errorPos, Res.FunctionRequiresOneOrTwoArgs, functionName); } - // As(...) function - private Expression ParseFunctionAs() + Expression typeArgument; + Expression it; + if (args.Length == 1) { - int errorPos = _textParser.CurrentToken.Pos; - string functionName = _textParser.CurrentToken.Text; - _textParser.NextToken(); + typeArgument = args[0]; + it = _it!; + } + else + { + typeArgument = args[1]; + it = args[0]; + } - Expression[] args = ParseArgumentList(); + return Expression.TypeAs(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); + } - if (args.Length != 1 && args.Length != 2) - { - throw ParseError(errorPos, Res.FunctionRequiresOneOrTwoArgs, functionName); - } + // Cast(...) function + private Expression ParseFunctionCast() + { + int errorPos = _textParser.CurrentToken.Pos; + string functionName = _textParser.CurrentToken.Text; + _textParser.NextToken(); - Expression typeArgument; - Expression it; - if (args.Length == 1) - { - typeArgument = args[0]; - it = _it!; - } - else - { - typeArgument = args[1]; - it = args[0]; - } + Expression[] args = ParseArgumentList(); - return Expression.TypeAs(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); + if (args.Length != 1 && args.Length != 2) + { + throw ParseError(errorPos, Res.FunctionRequiresOneOrTwoArgs, functionName); } - // Cast(...) function - private Expression ParseFunctionCast() + Expression typeArgument; + Expression it; + if (args.Length == 1) { - int errorPos = _textParser.CurrentToken.Pos; - string functionName = _textParser.CurrentToken.Text; - _textParser.NextToken(); - - Expression[] args = ParseArgumentList(); - - if (args.Length != 1 && args.Length != 2) - { - throw ParseError(errorPos, Res.FunctionRequiresOneOrTwoArgs, functionName); - } + typeArgument = args[0]; + it = _it!; + } + else + { + typeArgument = args[1]; + it = args[0]; + } - Expression typeArgument; - Expression it; - if (args.Length == 1) - { - typeArgument = args[0]; - it = _it!; - } - else - { - typeArgument = args[1]; - it = args[0]; - } + return Expression.ConvertChecked(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); + } - return Expression.ConvertChecked(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); + private Expression GenerateConditional(Expression test, Expression expressionIfTrue, Expression expressionIfFalse, bool nullPropagating, int errorPos) + { + if (test.Type != typeof(bool)) + { + throw ParseError(errorPos, Res.FirstExprMustBeBool); } - private Expression GenerateConditional(Expression test, Expression expressionIfTrue, Expression expressionIfFalse, bool nullPropagating, int errorPos) + if (expressionIfTrue.Type != expressionIfFalse.Type) { - if (test.Type != typeof(bool)) - { - throw ParseError(errorPos, Res.FirstExprMustBeBool); - } - - if (expressionIfTrue.Type != expressionIfFalse.Type) + // If expressionIfTrue is a null constant and expressionIfFalse is ValueType: + if (Constants.IsNull(expressionIfTrue) && expressionIfFalse.Type.GetTypeInfo().IsValueType) { - // If expressionIfTrue is a null constant and expressionIfFalse is ValueType: - if (Constants.IsNull(expressionIfTrue) && expressionIfFalse.Type.GetTypeInfo().IsValueType) + if (nullPropagating && _parsingConfig.NullPropagatingUseDefaultValueForNonNullableValueTypes) { - if (nullPropagating && _parsingConfig.NullPropagatingUseDefaultValueForNonNullableValueTypes) - { - // If expressionIfFalse is a non-nullable type: - // generate default expression from the expressionIfFalse-type for expressionIfTrue - // Else - // create nullable constant from expressionIfTrue with type from expressionIfFalse + // If expressionIfFalse is a non-nullable type: + // generate default expression from the expressionIfFalse-type for expressionIfTrue + // Else + // create nullable constant from expressionIfTrue with type from expressionIfFalse - if (!TypeHelper.IsNullableType(expressionIfFalse.Type)) - { - expressionIfTrue = _expressionHelper.GenerateDefaultExpression(expressionIfFalse.Type); - } - else - { - expressionIfTrue = Expression.Constant(null, expressionIfFalse.Type); - } + if (!TypeHelper.IsNullableType(expressionIfFalse.Type)) + { + expressionIfTrue = _expressionHelper.GenerateDefaultExpression(expressionIfFalse.Type); } else { - // - create nullable constant from expressionIfTrue with type from expressionIfFalse - // - convert expressionIfFalse to nullable (unless it's already nullable) - var nullableType = TypeHelper.ToNullableType(expressionIfFalse.Type); - expressionIfTrue = Expression.Constant(null, nullableType); - - if (!TypeHelper.IsNullableType(expressionIfFalse.Type)) - { - expressionIfFalse = Expression.Convert(expressionIfFalse, nullableType); - } + expressionIfTrue = Expression.Constant(null, expressionIfFalse.Type); } - - return Expression.Condition(test, expressionIfTrue, expressionIfFalse); } - - // If expressionIfFalse is a null constant and expressionIfTrue is a ValueType: - if (Constants.IsNull(expressionIfFalse) && expressionIfTrue.Type.GetTypeInfo().IsValueType) + else { - if (nullPropagating && _parsingConfig.NullPropagatingUseDefaultValueForNonNullableValueTypes) - { - // If expressionIfTrue is a non-nullable type: - // generate default expression from the expressionIfFalse-type for expressionIfFalse - // Else - // create nullable constant from expressionIfFalse with type from expressionIfTrue + // - create nullable constant from expressionIfTrue with type from expressionIfFalse + // - convert expressionIfFalse to nullable (unless it's already nullable) + var nullableType = TypeHelper.ToNullableType(expressionIfFalse.Type); + expressionIfTrue = Expression.Constant(null, nullableType); - if (!TypeHelper.IsNullableType(expressionIfTrue.Type)) - { - expressionIfFalse = _expressionHelper.GenerateDefaultExpression(expressionIfTrue.Type); - } - else - { - expressionIfFalse = Expression.Constant(null, expressionIfTrue.Type); - } - } - else + if (!TypeHelper.IsNullableType(expressionIfFalse.Type)) { - // - create nullable constant from expressionIfFalse with type from expressionIfTrue - // - convert expressionIfTrue to nullable (unless it's already nullable) - - Type nullableType = TypeHelper.ToNullableType(expressionIfTrue.Type); - expressionIfFalse = Expression.Constant(null, nullableType); - if (!TypeHelper.IsNullableType(expressionIfTrue.Type)) - { - expressionIfTrue = Expression.Convert(expressionIfTrue, nullableType); - } + expressionIfFalse = Expression.Convert(expressionIfFalse, nullableType); } - - return Expression.Condition(test, expressionIfTrue, expressionIfFalse); } - var expr1As2 = !Constants.IsNull(expressionIfFalse) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfTrue, expressionIfFalse.Type, true, false) : null; - var expr2As1 = !Constants.IsNull(expressionIfTrue) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfFalse, expressionIfTrue.Type, true, false) : null; - if (expr1As2 != null && expr2As1 == null) - { - expressionIfTrue = expr1As2; - } - else if (expr2As1 != null && expr1As2 == null) + return Expression.Condition(test, expressionIfTrue, expressionIfFalse); + } + + // If expressionIfFalse is a null constant and expressionIfTrue is a ValueType: + if (Constants.IsNull(expressionIfFalse) && expressionIfTrue.Type.GetTypeInfo().IsValueType) + { + if (nullPropagating && _parsingConfig.NullPropagatingUseDefaultValueForNonNullableValueTypes) { - expressionIfFalse = expr2As1; + // If expressionIfTrue is a non-nullable type: + // generate default expression from the expressionIfFalse-type for expressionIfFalse + // Else + // create nullable constant from expressionIfFalse with type from expressionIfTrue + + if (!TypeHelper.IsNullableType(expressionIfTrue.Type)) + { + expressionIfFalse = _expressionHelper.GenerateDefaultExpression(expressionIfTrue.Type); + } + else + { + expressionIfFalse = Expression.Constant(null, expressionIfTrue.Type); + } } else { - string type1 = !Constants.IsNull(expressionIfTrue) ? expressionIfTrue.Type.Name : "null"; - string type2 = !Constants.IsNull(expressionIfFalse) ? expressionIfFalse.Type.Name : "null"; - if (expr1As2 != null) + // - create nullable constant from expressionIfFalse with type from expressionIfTrue + // - convert expressionIfTrue to nullable (unless it's already nullable) + + Type nullableType = TypeHelper.ToNullableType(expressionIfTrue.Type); + expressionIfFalse = Expression.Constant(null, nullableType); + if (!TypeHelper.IsNullableType(expressionIfTrue.Type)) { - throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2); + expressionIfTrue = Expression.Convert(expressionIfTrue, nullableType); } + } - throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2); + return Expression.Condition(test, expressionIfTrue, expressionIfFalse); + } + + var expr1As2 = !Constants.IsNull(expressionIfFalse) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfTrue, expressionIfFalse.Type, true, false) : null; + var expr2As1 = !Constants.IsNull(expressionIfTrue) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfFalse, expressionIfTrue.Type, true, false) : null; + if (expr1As2 != null && expr2As1 == null) + { + expressionIfTrue = expr1As2; + } + else if (expr2As1 != null && expr1As2 == null) + { + expressionIfFalse = expr2As1; + } + else + { + string type1 = !Constants.IsNull(expressionIfTrue) ? expressionIfTrue.Type.Name : "null"; + string type2 = !Constants.IsNull(expressionIfFalse) ? expressionIfFalse.Type.Name : "null"; + if (expr1As2 != null) + { + throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2); } + + throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2); } + } + + return Expression.Condition(test, expressionIfTrue, expressionIfFalse); + } - return Expression.Condition(test, expressionIfTrue, expressionIfFalse); + // new (...) function + private Expression ParseNew() + { + _textParser.NextToken(); + if (_textParser.CurrentToken.Id != TokenId.OpenParen && + _textParser.CurrentToken.Id != TokenId.OpenCurlyParen && + _textParser.CurrentToken.Id != TokenId.OpenBracket && + _textParser.CurrentToken.Id != TokenId.Identifier) + { + throw ParseError(Res.OpenParenOrIdentifierExpected); } - // new (...) function - private Expression ParseNew() + Type? newType = null; + if (_textParser.CurrentToken.Id == TokenId.Identifier) { + var newTypeName = _textParser.CurrentToken.Text; _textParser.NextToken(); - if (_textParser.CurrentToken.Id != TokenId.OpenParen && - _textParser.CurrentToken.Id != TokenId.OpenCurlyParen && - _textParser.CurrentToken.Id != TokenId.OpenBracket && - _textParser.CurrentToken.Id != TokenId.Identifier) - { - throw ParseError(Res.OpenParenOrIdentifierExpected); - } - Type? newType = null; - if (_textParser.CurrentToken.Id == TokenId.Identifier) + while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) { - var newTypeName = _textParser.CurrentToken.Text; + var sep = _textParser.CurrentToken.Text; _textParser.NextToken(); - - while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) - { - var sep = _textParser.CurrentToken.Text; - _textParser.NextToken(); - if (_textParser.CurrentToken.Id != TokenId.Identifier) - { - throw ParseError(Res.IdentifierExpected); - } - newTypeName += sep + _textParser.CurrentToken.Text; - _textParser.NextToken(); - } - - newType = _typeFinder.FindTypeByName(newTypeName, new[] { _it, _parent, _root }, false); - if (newType == null) + if (_textParser.CurrentToken.Id != TokenId.Identifier) { - throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, newTypeName); + throw ParseError(Res.IdentifierExpected); } + newTypeName += sep + _textParser.CurrentToken.Text; + _textParser.NextToken(); + } - if (_textParser.CurrentToken.Id != TokenId.OpenParen && - _textParser.CurrentToken.Id != TokenId.OpenBracket && - _textParser.CurrentToken.Id != TokenId.OpenCurlyParen) - { - throw ParseError(Res.OpenParenExpected); - } + newType = _typeFinder.FindTypeByName(newTypeName, new[] { _it, _parent, _root }, false); + if (newType == null) + { + throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, newTypeName); } - bool arrayInitializer = false; - if (_textParser.CurrentToken.Id == TokenId.OpenBracket) + if (_textParser.CurrentToken.Id != TokenId.OpenParen && + _textParser.CurrentToken.Id != TokenId.OpenBracket && + _textParser.CurrentToken.Id != TokenId.OpenCurlyParen) { - _textParser.NextToken(); - _textParser.ValidateToken(TokenId.CloseBracket, Res.CloseBracketExpected); - _textParser.NextToken(); - _textParser.ValidateToken(TokenId.OpenCurlyParen, Res.OpenCurlyParenExpected); - arrayInitializer = true; + throw ParseError(Res.OpenParenExpected); } + } + bool arrayInitializer = false; + if (_textParser.CurrentToken.Id == TokenId.OpenBracket) + { _textParser.NextToken(); + _textParser.ValidateToken(TokenId.CloseBracket, Res.CloseBracketExpected); + _textParser.NextToken(); + _textParser.ValidateToken(TokenId.OpenCurlyParen, Res.OpenCurlyParenExpected); + arrayInitializer = true; + } - var properties = new List(); - var expressions = new List(); + _textParser.NextToken(); - while (_textParser.CurrentToken.Id != TokenId.CloseParen && _textParser.CurrentToken.Id != TokenId.CloseCurlyParen) + var properties = new List(); + var expressions = new List(); + + while (_textParser.CurrentToken.Id != TokenId.CloseParen && _textParser.CurrentToken.Id != TokenId.CloseCurlyParen) + { + int exprPos = _textParser.CurrentToken.Pos; + Expression expr = ParseConditionalOperator(); + if (!arrayInitializer) { - int exprPos = _textParser.CurrentToken.Pos; - Expression expr = ParseConditionalOperator(); - if (!arrayInitializer) + string? propName; + if (TokenIdentifierIs("as")) { - string? propName; - if (TokenIdentifierIs("as")) - { - _textParser.NextToken(); - propName = GetIdentifier(); - _textParser.NextToken(); - } - else + _textParser.NextToken(); + propName = GetIdentifier(); + _textParser.NextToken(); + } + else + { + if (!TryGetMemberName(expr, out propName)) // TODO : investigate this { - if (!TryGetMemberName(expr, out propName)) // TODO : investigate this + if (expr is MethodCallExpression methodCallExpression + && methodCallExpression.Arguments.Count == 1 + && methodCallExpression.Arguments[0] is ConstantExpression methodCallExpressionArgument + && methodCallExpressionArgument.Type == typeof(string) + && properties.All(x => x.Name != (string)methodCallExpressionArgument.Value)) { - if (expr is MethodCallExpression methodCallExpression - && methodCallExpression.Arguments.Count == 1 - && methodCallExpression.Arguments[0] is ConstantExpression methodCallExpressionArgument - && methodCallExpressionArgument.Type == typeof(string) - && properties.All(x => x.Name != (string)methodCallExpressionArgument.Value)) - { - propName = (string)methodCallExpressionArgument.Value; - } - else - { - throw ParseError(exprPos, Res.MissingAsClause); - } + propName = (string)methodCallExpressionArgument.Value; + } + else + { + throw ParseError(exprPos, Res.MissingAsClause); } - } - - if (!string.IsNullOrEmpty(propName)) - { - properties.Add(new DynamicProperty(propName!, expr.Type)); } } - expressions.Add(expr); - - if (_textParser.CurrentToken.Id != TokenId.Comma) + if (!string.IsNullOrEmpty(propName)) { - break; + properties.Add(new DynamicProperty(propName!, expr.Type)); } - - _textParser.NextToken(); } - if (_textParser.CurrentToken.Id != TokenId.CloseParen && _textParser.CurrentToken.Id != TokenId.CloseCurlyParen) - { - throw ParseError(Res.CloseParenOrCommaExpected); - } - _textParser.NextToken(); + expressions.Add(expr); - if (arrayInitializer) + if (_textParser.CurrentToken.Id != TokenId.Comma) { - return CreateArrayInitializerExpression(expressions, newType); + break; } - return CreateNewExpression(properties, expressions, newType); + _textParser.NextToken(); } - private Expression CreateArrayInitializerExpression(List expressions, Type? newType) + if (_textParser.CurrentToken.Id != TokenId.CloseParen && _textParser.CurrentToken.Id != TokenId.CloseCurlyParen) { - if (expressions.Count == 0) - { - return Expression.NewArrayInit(newType ?? typeof(object)); - } + throw ParseError(Res.CloseParenOrCommaExpected); + } + _textParser.NextToken(); - if (newType != null) - { - return Expression.NewArrayInit(newType, expressions.Select(expression => _parsingConfig.ExpressionPromoter.Promote(expression, newType, true, true))); - } + if (arrayInitializer) + { + return CreateArrayInitializerExpression(expressions, newType); + } + + return CreateNewExpression(properties, expressions, newType); + } - return Expression.NewArrayInit(expressions.All(expression => expression.Type == expressions[0].Type) ? expressions[0].Type : typeof(object), expressions); + private Expression CreateArrayInitializerExpression(List expressions, Type? newType) + { + if (expressions.Count == 0) + { + return Expression.NewArrayInit(newType ?? typeof(object)); } - private Expression CreateNewExpression(List properties, List expressions, Type? newType) + if (newType != null) { - // http://solutionizing.net/category/linq/ - Type? type = newType ?? _resultType; + return Expression.NewArrayInit(newType, expressions.Select(expression => _parsingConfig.ExpressionPromoter.Promote(expression, newType, true, true))); + } - if (type == null) - { + return Expression.NewArrayInit(expressions.All(expression => expression.Type == expressions[0].Type) ? expressions[0].Type : typeof(object), expressions); + } + + private Expression CreateNewExpression(List properties, List expressions, Type? newType) + { + // http://solutionizing.net/category/linq/ + Type? type = newType ?? _resultType; + + if (type == null) + { #if UAP10_0 - type = typeof(DynamicClass); - Type typeForKeyValuePair = typeof(KeyValuePair); + type = typeof(DynamicClass); + Type typeForKeyValuePair = typeof(KeyValuePair); - ConstructorInfo constructorForKeyValuePair = typeForKeyValuePair.GetTypeInfo().DeclaredConstructors.First(); + ConstructorInfo constructorForKeyValuePair = typeForKeyValuePair.GetTypeInfo().DeclaredConstructors.First(); - var arrayIndexParams = new List(); - for (int i = 0; i < expressions.Count; i++) - { - // Just convert the expression always to an object expression. - UnaryExpression boxingExpression = Expression.Convert(expressions[i], typeof(object)); - NewExpression parameter = Expression.New(constructorForKeyValuePair, (Expression)Expression.Constant(properties[i].Name), boxingExpression); + var arrayIndexParams = new List(); + for (int i = 0; i < expressions.Count; i++) + { + // Just convert the expression always to an object expression. + UnaryExpression boxingExpression = Expression.Convert(expressions[i], typeof(object)); + NewExpression parameter = Expression.New(constructorForKeyValuePair, (Expression)Expression.Constant(properties[i].Name), boxingExpression); - arrayIndexParams.Add(parameter); - } + arrayIndexParams.Add(parameter); + } - // Create an expression tree that represents creating and initializing a one-dimensional array of type KeyValuePair. - NewArrayExpression newArrayExpression = Expression.NewArrayInit(typeof(KeyValuePair), arrayIndexParams); + // Create an expression tree that represents creating and initializing a one-dimensional array of type KeyValuePair. + NewArrayExpression newArrayExpression = Expression.NewArrayInit(typeof(KeyValuePair), arrayIndexParams); - // Get the "public DynamicClass(KeyValuePair[] propertylist)" constructor - ConstructorInfo constructor = type.GetTypeInfo().DeclaredConstructors.First(); + // Get the "public DynamicClass(KeyValuePair[] propertylist)" constructor + ConstructorInfo constructor = type.GetTypeInfo().DeclaredConstructors.First(); - return Expression.New(constructor, newArrayExpression); + return Expression.New(constructor, newArrayExpression); #else - type = DynamicClassFactory.CreateType(properties, _createParameterCtor); + type = DynamicClassFactory.CreateType(properties, _createParameterCtor); #endif - } + } - // Option 1. Try to bind via properties (TODO : investigate if this code block is 100% correct and is needed) - var propertyInfos = type.GetProperties(); - if (type.GetTypeInfo().BaseType == typeof(DynamicClass)) - { - propertyInfos = propertyInfos.Where(x => x.Name != "Item").ToArray(); - } - var propertyTypes = propertyInfos.Select(p => p.PropertyType).ToArray(); - var ctor = type.GetConstructor(propertyTypes); - if (ctor != null) + // Option 1. Try to bind via properties (TODO : investigate if this code block is 100% correct and is needed) + var propertyInfos = type.GetProperties(); + if (type.GetTypeInfo().BaseType == typeof(DynamicClass)) + { + propertyInfos = propertyInfos.Where(x => x.Name != "Item").ToArray(); + } + var propertyTypes = propertyInfos.Select(p => p.PropertyType).ToArray(); + var ctor = type.GetConstructor(propertyTypes); + if (ctor != null) + { + var constructorParameters = ctor.GetParameters(); + if (constructorParameters.Length == expressions.Count) { - var constructorParameters = ctor.GetParameters(); - if (constructorParameters.Length == expressions.Count) - { - bool bindParametersSequentially = !properties.All(p => constructorParameters - .Any(cp => cp.Name == p.Name && (cp.ParameterType == p.Type || p.Type == Nullable.GetUnderlyingType(cp.ParameterType)))); - var expressionsPromoted = new List(); + bool bindParametersSequentially = !properties.All(p => constructorParameters + .Any(cp => cp.Name == p.Name && (cp.ParameterType == p.Type || p.Type == Nullable.GetUnderlyingType(cp.ParameterType)))); + var expressionsPromoted = new List(); - // Loop all expressions and promote if needed - for (int i = 0; i < constructorParameters.Length; i++) + // Loop all expressions and promote if needed + for (int i = 0; i < constructorParameters.Length; i++) + { + if (bindParametersSequentially) { - if (bindParametersSequentially) - { - expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyTypes[i], true, true)); - } - else - { - Type propertyType = constructorParameters[i].ParameterType; - string cParameterName = constructorParameters[i].Name; - var propertyAndIndex = properties.Select((p, index) => new { p, index }) - .First(p => p.p.Name == cParameterName && (p.p.Type == propertyType || p.p.Type == Nullable.GetUnderlyingType(propertyType))); - // Promote from Type to Nullable Type if needed - expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true)); - } + expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyTypes[i], true, true)); + } + else + { + Type propertyType = constructorParameters[i].ParameterType; + string cParameterName = constructorParameters[i].Name; + var propertyAndIndex = properties.Select((p, index) => new { p, index }) + .First(p => p.p.Name == cParameterName && (p.p.Type == propertyType || p.p.Type == Nullable.GetUnderlyingType(propertyType))); + // Promote from Type to Nullable Type if needed + expressionsPromoted.Add(_parsingConfig.ExpressionPromoter.Promote(expressions[propertyAndIndex.index], propertyType, true, true)); } - - return Expression.New(ctor, expressionsPromoted, (IEnumerable)propertyInfos); } + + return Expression.New(ctor, expressionsPromoted, (IEnumerable)propertyInfos); } + } - // Option 2. Try to find a constructor with the exact argument-types and exact same order - var constructorArgumentTypes = properties.Select(p => p.Type).ToArray(); - var exactConstructor = type.GetConstructor(constructorArgumentTypes); - if (exactConstructor != null) - { - // Promote from Type to Nullable Type if needed - var expressionsPromoted = exactConstructor.GetParameters() - .Select((t, i) => _parsingConfig.ExpressionPromoter.Promote(expressions[i], t.ParameterType, true, true)) - .ToArray(); + // Option 2. Try to find a constructor with the exact argument-types and exact same order + var constructorArgumentTypes = properties.Select(p => p.Type).ToArray(); + var exactConstructor = type.GetConstructor(constructorArgumentTypes); + if (exactConstructor != null) + { + // Promote from Type to Nullable Type if needed + var expressionsPromoted = exactConstructor.GetParameters() + .Select((t, i) => _parsingConfig.ExpressionPromoter.Promote(expressions[i], t.ParameterType, true, true)) + .ToArray(); - return Expression.New(exactConstructor, expressionsPromoted); - } + return Expression.New(exactConstructor, expressionsPromoted); + } - // Option 2. Call the default (empty) constructor and set the members - var memberBindings = new MemberBinding[properties.Count]; - for (int i = 0; i < memberBindings.Length; i++) + // Option 2. Call the default (empty) constructor and set the members + var memberBindings = new MemberBinding[properties.Count]; + for (int i = 0; i < memberBindings.Length; i++) + { + string propertyOrFieldName = properties[i].Name; + Type propertyOrFieldType; + MemberInfo memberInfo; + var propertyInfo = type.GetProperty(propertyOrFieldName); + if (propertyInfo != null) + { + memberInfo = propertyInfo; + propertyOrFieldType = propertyInfo.PropertyType; + } + else { - string propertyOrFieldName = properties[i].Name; - Type propertyOrFieldType; - MemberInfo memberInfo; - var propertyInfo = type.GetProperty(propertyOrFieldName); - if (propertyInfo != null) + var fieldInfo = type.GetField(propertyOrFieldName); + if (fieldInfo == null) { - memberInfo = propertyInfo; - propertyOrFieldType = propertyInfo.PropertyType; + throw ParseError(Res.UnknownPropertyOrField, propertyOrFieldName, TypeHelper.GetTypeName(type)); } - else - { - var fieldInfo = type.GetField(propertyOrFieldName); - if (fieldInfo == null) - { - throw ParseError(Res.UnknownPropertyOrField, propertyOrFieldName, TypeHelper.GetTypeName(type)); - } - memberInfo = fieldInfo; - propertyOrFieldType = fieldInfo.FieldType; - } + memberInfo = fieldInfo; + propertyOrFieldType = fieldInfo.FieldType; + } - // Promote from Type to Nullable Type if needed - var promoted = _parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyOrFieldType, true, true); - if (promoted is null) - { - throw new NotSupportedException($"Unable to promote expression '{expressions[i]}'."); - } - memberBindings[i] = Expression.Bind(memberInfo, promoted); + // Promote from Type to Nullable Type if needed + var promoted = _parsingConfig.ExpressionPromoter.Promote(expressions[i], propertyOrFieldType, true, true); + if (promoted is null) + { + throw new NotSupportedException($"Unable to promote expression '{expressions[i]}'."); } + memberBindings[i] = Expression.Bind(memberInfo, promoted); + } + + return Expression.MemberInit(Expression.New(type), memberBindings); + } + + private Expression ParseLambdaInvocation(LambdaExpression lambda) + { + int errorPos = _textParser.CurrentToken.Pos; + _textParser.NextToken(); + Expression[] args = ParseArgumentList(); - return Expression.MemberInit(Expression.New(type), memberBindings); + Expression? nullExpressionReference = null; + if (_methodFinder.FindMethod(lambda.Type, nameof(Expression.Invoke), false, ref nullExpressionReference, ref args, out _) != 1) + { + throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda); } - private Expression ParseLambdaInvocation(LambdaExpression lambda) + return Expression.Invoke(lambda, args); + } + + private Expression ParseTypeAccess(Type type, bool getNext) + { + int errorPos = _textParser.CurrentToken.Pos; + if (getNext) { - int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); - Expression[] args = ParseArgumentList(); + } - Expression? nullExpressionReference = null; - if (_methodFinder.FindMethod(lambda.Type, nameof(Expression.Invoke), false, ref nullExpressionReference, ref args, out _) != 1) + if (_textParser.CurrentToken.Id == TokenId.Question) + { + if (!type.GetTypeInfo().IsValueType || TypeHelper.IsNullableType(type)) { - throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda); + throw ParseError(errorPos, Res.TypeHasNoNullableForm, TypeHelper.GetTypeName(type)); } - return Expression.Invoke(lambda, args); + type = typeof(Nullable<>).MakeGenericType(type); + _textParser.NextToken(); } - private Expression ParseTypeAccess(Type type, bool getNext) + // This is a shorthand for explicitly converting a string to something + bool shorthand = _textParser.CurrentToken.Id == TokenId.StringLiteral; + if (_textParser.CurrentToken.Id == TokenId.OpenParen || shorthand) { - int errorPos = _textParser.CurrentToken.Pos; - if (getNext) + Expression[] args; + if (shorthand) { - _textParser.NextToken(); + var expressionOrType = ParseStringLiteral(true); + args = new[] { expressionOrType.First }; } - - if (_textParser.CurrentToken.Id == TokenId.Question) + else { - if (!type.GetTypeInfo().IsValueType || TypeHelper.IsNullableType(type)) - { - throw ParseError(errorPos, Res.TypeHasNoNullableForm, TypeHelper.GetTypeName(type)); - } - - type = typeof(Nullable<>).MakeGenericType(type); - _textParser.NextToken(); + args = ParseArgumentList(); } - // This is a shorthand for explicitly converting a string to something - bool shorthand = _textParser.CurrentToken.Id == TokenId.StringLiteral; - if (_textParser.CurrentToken.Id == TokenId.OpenParen || shorthand) + // If only 1 argument and + // - the arg is ConstantExpression, return the conversion + // OR + // - the arg is null, return the conversion (Can't use constructor) + // + // Then try to GenerateConversion + + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (args.Length == 1 && (args[0] == null || args[0] is ConstantExpression) && TryGenerateConversion(args[0], type, out var generatedExpression)) { - Expression[] args; - if (shorthand) - { - var expressionOrType = ParseStringLiteral(true); - args = new[] { expressionOrType.First }; - } - else - { - args = ParseArgumentList(); - } + return generatedExpression!; + } - // If only 1 argument and - // - the arg is ConstantExpression, return the conversion - // OR - // - the arg is null, return the conversion (Can't use constructor) - // - // Then try to GenerateConversion + // If only 1 argument, and if the type is a ValueType and argType is also a ValueType, just Convert + if (args.Length == 1) + { + Type argType = args[0].Type; - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract - if (args.Length == 1 && (args[0] == null || args[0] is ConstantExpression) && TryGenerateConversion(args[0], type, out var generatedExpression)) + if (type.GetTypeInfo().IsValueType && TypeHelper.IsNullableType(type) && argType.GetTypeInfo().IsValueType) { - return generatedExpression!; + return Expression.Convert(args[0], type); } + } - // If only 1 argument, and if the type is a ValueType and argType is also a ValueType, just Convert - if (args.Length == 1) - { - Type argType = args[0].Type; - - if (type.GetTypeInfo().IsValueType && TypeHelper.IsNullableType(type) && argType.GetTypeInfo().IsValueType) + var constructorsWithOutPointerArguments = type.GetConstructors() + .Where(c => !c.GetParameters().Any(p => p.ParameterType.GetTypeInfo().IsPointer)) + .ToArray(); + switch (_methodFinder.FindBestMethodBasedOnArguments(constructorsWithOutPointerArguments, ref args, out var method)) + { + case 0: + if (args.Length == 1 && TryGenerateConversion(args[0], type, out generatedExpression)) { - return Expression.Convert(args[0], type); + return generatedExpression!; } - } - - var constructorsWithOutPointerArguments = type.GetConstructors() - .Where(c => !c.GetParameters().Any(p => p.ParameterType.GetTypeInfo().IsPointer)) - .ToArray(); - switch (_methodFinder.FindBestMethodBasedOnArguments(constructorsWithOutPointerArguments, ref args, out var method)) - { - case 0: - if (args.Length == 1 && TryGenerateConversion(args[0], type, out generatedExpression)) - { - return generatedExpression!; - } - throw ParseError(errorPos, Res.NoMatchingConstructor, TypeHelper.GetTypeName(type)); + throw ParseError(errorPos, Res.NoMatchingConstructor, TypeHelper.GetTypeName(type)); - case 1: - return Expression.New((ConstructorInfo)method!, args); + case 1: + return Expression.New((ConstructorInfo)method!, args); - default: - throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, TypeHelper.GetTypeName(type)); - } + default: + throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, TypeHelper.GetTypeName(type)); } + } - _textParser.ValidateToken(TokenId.Dot, Res.DotOrOpenParenOrStringLiteralExpected); - _textParser.NextToken(); + _textParser.ValidateToken(TokenId.Dot, Res.DotOrOpenParenOrStringLiteralExpected); + _textParser.NextToken(); - return ParseMemberAccess(type, null); + return ParseMemberAccess(type, null); + } + + private bool TryGenerateConversion(Expression sourceExpression, Type type, out Expression? expression) + { + Type exprType = sourceExpression.Type; + if (exprType == type) + { + expression = sourceExpression; + return true; } - private bool TryGenerateConversion(Expression sourceExpression, Type type, out Expression? expression) + if (exprType.GetTypeInfo().IsValueType && type.GetTypeInfo().IsValueType) { - Type exprType = sourceExpression.Type; - if (exprType == type) + if ((TypeHelper.IsNullableType(exprType) || TypeHelper.IsNullableType(type)) && TypeHelper.GetNonNullableType(exprType) == TypeHelper.GetNonNullableType(type)) { - expression = sourceExpression; + expression = Expression.Convert(sourceExpression, type); return true; } - if (exprType.GetTypeInfo().IsValueType && type.GetTypeInfo().IsValueType) - { - if ((TypeHelper.IsNullableType(exprType) || TypeHelper.IsNullableType(type)) && TypeHelper.GetNonNullableType(exprType) == TypeHelper.GetNonNullableType(type)) - { - expression = Expression.Convert(sourceExpression, type); - return true; - } - - if ((TypeHelper.IsNumericType(exprType) || TypeHelper.IsEnumType(exprType)) && TypeHelper.IsNumericType(type) || TypeHelper.IsEnumType(type)) - { - expression = Expression.ConvertChecked(sourceExpression, type); - return true; - } - } - - if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) || exprType.GetTypeInfo().IsInterface || type.GetTypeInfo().IsInterface) + if ((TypeHelper.IsNumericType(exprType) || TypeHelper.IsEnumType(exprType)) && TypeHelper.IsNumericType(type) || TypeHelper.IsEnumType(type)) { - expression = Expression.Convert(sourceExpression, type); + expression = Expression.ConvertChecked(sourceExpression, type); return true; } + } - // Try to Parse the string rather than just generate the convert statement - if (sourceExpression.NodeType == ExpressionType.Constant && exprType == typeof(string)) - { - string text = (string)((ConstantExpression)sourceExpression).Value; + if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) || exprType.GetTypeInfo().IsInterface || type.GetTypeInfo().IsInterface) + { + expression = Expression.Convert(sourceExpression, type); + return true; + } - var typeConvertor = _typeConverterFactory.GetConverter(type); - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract - if (typeConvertor != null && typeConvertor.CanConvertFrom(typeof(string))) - { - var value = typeConvertor.ConvertFromInvariantString(text); - expression = Expression.Constant(value, type); - return true; - } - } + // Try to Parse the string rather than just generate the convert statement + if (sourceExpression.NodeType == ExpressionType.Constant && exprType == typeof(string)) + { + string text = (string)((ConstantExpression)sourceExpression).Value; - // Check if there are any explicit conversion operators on the source type which fit the requirement (cast to the return type). - bool explicitOperatorAvailable = exprType.GetTypeInfo().GetDeclaredMethods("op_Explicit").Any(m => m.ReturnType == type); - if (explicitOperatorAvailable) + var typeConvertor = _typeConverterFactory.GetConverter(type); + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (typeConvertor != null && typeConvertor.CanConvertFrom(typeof(string))) { - expression = Expression.Convert(sourceExpression, type); + var value = typeConvertor.ConvertFromInvariantString(text); + expression = Expression.Constant(value, type); return true; } + } - expression = null; - return false; + // Check if there are any explicit conversion operators on the source type which fit the requirement (cast to the return type). + bool explicitOperatorAvailable = exprType.GetTypeInfo().GetDeclaredMethods("op_Explicit").Any(m => m.ReturnType == type); + if (explicitOperatorAvailable) + { + expression = Expression.Convert(sourceExpression, type); + return true; } - private Expression ParseMemberAccess(Type? type, Expression? expression) + expression = null; + return false; + } + + private Expression ParseMemberAccess(Type? type, Expression? expression) + { + if (expression != null) { - if (expression != null) - { - type = expression.Type; - } + type = expression.Type; + } - int errorPos = _textParser.CurrentToken.Pos; - string id = GetIdentifier(); - _textParser.NextToken(); + int errorPos = _textParser.CurrentToken.Pos; + string id = GetIdentifier(); + _textParser.NextToken(); - if (_textParser.CurrentToken.Id == TokenId.OpenParen) + if (_textParser.CurrentToken.Id == TokenId.OpenParen) + { + if (expression != null && type != typeof(string)) { - if (expression != null && type != typeof(string)) - { - var enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type); - if (enumerableType != null) - { - Type elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0]; - return ParseEnumerable(expression, elementType, id, errorPos, type); - } - } - - Expression[] args = ParseArgumentList(); - switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out var mb)) + var enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type); + if (enumerableType != null) { - case 0: - throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type)); - - case 1: - MethodInfo method = (MethodInfo)mb!; - if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) - { - throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType!)); - } - - if (method.IsGenericMethod) - { - var genericParameters = method.GetParameters().Where(p => p.ParameterType.IsGenericParameter); - var typeArguments = genericParameters.Select(a => args[a.Position].Type); - var constructedMethod = method.MakeGenericMethod(typeArguments.ToArray()); - return Expression.Call(expression, constructedMethod, args); - } - - return Expression.Call(expression, method, args); - - default: - throw ParseError(errorPos, Res.AmbiguousMethodInvocation, id, TypeHelper.GetTypeName(type)); + Type elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0]; + return ParseEnumerable(expression, elementType, id, errorPos, type); } } - var @enum = TypeHelper.ParseEnum(id, type); - if (@enum != null) + Expression[] args = ParseArgumentList(); + switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out var mb)) { - return Expression.Constant(@enum); - } + case 0: + throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type)); -#if UAP10_0 || NETSTANDARD1_3 - if (type == typeof(DynamicClass)) - { - return Expression.MakeIndex(expression, typeof(DynamicClass).GetProperty("Item"), new[] { Expression.Constant(id) }); - } -#endif - MemberInfo? member = FindPropertyOrField(type!, id, expression == null); - if (member is PropertyInfo property) - { - return Expression.Property(expression, property); - } + case 1: + MethodInfo method = (MethodInfo)mb!; + if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) + { + throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType!)); + } - if (member is FieldInfo field) - { - return Expression.Field(expression, field); - } + if (method.IsGenericMethod) + { + var genericParameters = method.GetParameters().Where(p => p.ParameterType.IsGenericParameter); + var typeArguments = genericParameters.Select(a => args[a.Position].Type); + var constructedMethod = method.MakeGenericMethod(typeArguments.ToArray()); + return Expression.Call(expression, constructedMethod, args); + } - // #357 #662 - var extraCheck = !_parsingConfig.PrioritizePropertyOrFieldOverTheType || - _parsingConfig.PrioritizePropertyOrFieldOverTheType && expression != null; + return Expression.Call(expression, method, args); - if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && extraCheck) - { - var indexerMethod = expression?.Type.GetMethod("get_Item", new[] { typeof(string) }); - if (indexerMethod != null) - { - return Expression.Call(expression, indexerMethod, Expression.Constant(id)); - } + default: + throw ParseError(errorPos, Res.AmbiguousMethodInvocation, id, TypeHelper.GetTypeName(type)); } + } -#if !NET35 && !UAP10_0 && !NETSTANDARD1_3 - if (type == typeof(object)) - { - // The member is a dynamic or ExpandoObject, so convert this - return _expressionHelper.ConvertToExpandoObjectAndCreateDynamicExpression(expression, type, id); - } + var @enum = TypeHelper.ParseEnum(id, type); + if (@enum != null) + { + return Expression.Constant(@enum); + } + +#if UAP10_0 || NETSTANDARD1_3 + if (type == typeof(DynamicClass)) + { + return Expression.MakeIndex(expression, typeof(DynamicClass).GetProperty("Item"), new[] { Expression.Constant(id) }); + } #endif - // Parse as Lambda - if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == type) - { - return ParseAsLambda(id); - } + MemberInfo? member = FindPropertyOrField(type!, id, expression == null); + if (member is PropertyInfo property) + { + return Expression.Property(expression, property); + } - // This could be enum like "A.B.C.MyEnum.Value1" or "A.B.C+MyEnum.Value1" - if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) + if (member is FieldInfo field) + { + return Expression.Field(expression, field); + } + + // #357 #662 + var extraCheck = !_parsingConfig.PrioritizePropertyOrFieldOverTheType || + _parsingConfig.PrioritizePropertyOrFieldOverTheType && expression != null; + + if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && extraCheck) + { + var indexerMethod = expression?.Type.GetMethod("get_Item", new[] { typeof(string) }); + if (indexerMethod != null) { - return ParseAsEnum(id); + return Expression.Call(expression, indexerMethod, Expression.Constant(id)); } + } - throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type)); +#if !NET35 && !UAP10_0 && !NETSTANDARD1_3 + if (type == typeof(object)) + { + // The member is a dynamic or ExpandoObject, so convert this + return _expressionHelper.ConvertToExpandoObjectAndCreateDynamicExpression(expression, type, id); + } +#endif + // Parse as Lambda + if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == type) + { + return ParseAsLambda(id); } - private Expression ParseAsLambda(string id) + // This could be enum like "A.B.C.MyEnum.Value1" or "A.B.C+MyEnum.Value1" + if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) { - // This might be an internal variable for use within a lambda expression, so store it as such - _internals.Add(id, _it!); - string previousItName = ItName; + return ParseAsEnum(id); + } - // Also store ItName (only once) - if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT)) - { - ItName = id; - } + throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type)); + } - // next - _textParser.NextToken(); + private Expression ParseAsLambda(string id) + { + // This might be an internal variable for use within a lambda expression, so store it as such + _internals.Add(id, _it!); + string previousItName = ItName; - LastLambdaItName = ItName; - var exp = ParseConditionalOperator(); + // Also store ItName (only once) + if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT)) + { + ItName = id; + } - // Restore previous context and clear internals - _internals.Remove(id); - ItName = previousItName; + // next + _textParser.NextToken(); - return exp; - } + LastLambdaItName = ItName; + var exp = ParseConditionalOperator(); - private Expression ParseAsEnum(string id) - { - var parts = new List { id }; + // Restore previous context and clear internals + _internals.Remove(id); + ItName = previousItName; - while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) - { - if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) - { - parts.Add(_textParser.CurrentToken.Text); - _textParser.NextToken(); - } + return exp; + } - if (_textParser.CurrentToken.Id == TokenId.Identifier) - { - parts.Add(_textParser.CurrentToken.Text); - _textParser.NextToken(); - } - } + private Expression ParseAsEnum(string id) + { + var parts = new List { id }; - var enumTypeAsString = string.Concat(parts.Take(parts.Count - 2).ToArray()); - var enumType = _typeFinder.FindTypeByName(enumTypeAsString, null, true); - if (enumType == null) + while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) + { + if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus) { - throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString); + parts.Add(_textParser.CurrentToken.Text); + _textParser.NextToken(); } - var enumValueAsString = parts.LastOrDefault(); - if (enumValueAsString == null) + if (_textParser.CurrentToken.Id == TokenId.Identifier) { - throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueExpected); + parts.Add(_textParser.CurrentToken.Text); + _textParser.NextToken(); } + } - var enumValue = TypeHelper.ParseEnum(enumValueAsString, enumType); - if (enumValue == null) - { - throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueNotDefined, enumValueAsString, enumTypeAsString); - } + var enumTypeAsString = string.Concat(parts.Take(parts.Count - 2).ToArray()); + var enumType = _typeFinder.FindTypeByName(enumTypeAsString, null, true); + if (enumType == null) + { + throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString); + } - return Expression.Constant(enumValue); + var enumValueAsString = parts.LastOrDefault(); + if (enumValueAsString == null) + { + throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueExpected); } - private Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type) + var enumValue = TypeHelper.ParseEnum(enumValueAsString, enumType); + if (enumValue == null) { - bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null; - bool isDictionary = TypeHelper.IsDictionary(type); + throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueNotDefined, enumValueAsString, enumTypeAsString); + } - var oldParent = _parent; + return Expression.Constant(enumValue); + } - ParameterExpression? outerIt = _it; - ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames); + private Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type) + { + bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null; + bool isDictionary = TypeHelper.IsDictionary(type); - _parent = _it; + var oldParent = _parent; - if (methodName == "Contains" || methodName == "ContainsKey" || methodName == "Skip" || methodName == "Take") - { - // for any method that acts on the parent element type, we need to specify the outerIt as scope. - _it = outerIt; - } - else - { - _it = innerIt; - } + ParameterExpression? outerIt = _it; + ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames); - Expression[] args = ParseArgumentList(); + _parent = _it; + if (methodName == "Contains" || methodName == "ContainsKey" || methodName == "Skip" || methodName == "Take") + { + // for any method that acts on the parent element type, we need to specify the outerIt as scope. _it = outerIt; - _parent = oldParent; + } + else + { + _it = innerIt; + } - if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, null, ref args)) - { - var method = type!.GetMethod(methodName)!; - return Expression.Call(instance, method, args); - } + Expression[] args = ParseArgumentList(); - if (!_methodFinder.ContainsMethod(typeof(IEnumerableSignatures), methodName, false, null, ref args)) - { - throw ParseError(errorPos, Res.NoApplicableAggregate, methodName, string.Join(",", args.Select(a => a.Type.Name).ToArray())); - } + _it = outerIt; + _parent = oldParent; - Type callType = typeof(Enumerable); - if (isQueryable && _methodFinder.ContainsMethod(typeof(IQueryableSignatures), methodName, false, null, ref args)) - { - callType = typeof(Queryable); - } + if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, null, ref args)) + { + var method = type!.GetMethod(methodName)!; + return Expression.Call(instance, method, args); + } - Type[] typeArgs; - if (new[] { "OfType", "Cast" }.Contains(methodName)) - { - if (args.Length != 1) - { - throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresOneArg, methodName); - } + if (!_methodFinder.ContainsMethod(typeof(IEnumerableSignatures), methodName, false, null, ref args)) + { + throw ParseError(errorPos, Res.NoApplicableAggregate, methodName, string.Join(",", args.Select(a => a.Type.Name).ToArray())); + } - typeArgs = new[] { ResolveTypeFromArgumentExpression(methodName, args[0]) }; - args = new Expression[0]; - } - else if (new[] { "Min", "Max", "Select", "OrderBy", "OrderByDescending", "ThenBy", "ThenByDescending", "GroupBy" }.Contains(methodName)) + Type callType = typeof(Enumerable); + if (isQueryable && _methodFinder.ContainsMethod(typeof(IQueryableSignatures), methodName, false, null, ref args)) + { + callType = typeof(Queryable); + } + + Type[] typeArgs; + if (new[] { "OfType", "Cast" }.Contains(methodName)) + { + if (args.Length != 1) { - if (args.Length == 2) - { - typeArgs = new[] { elementType, args[0].Type, args[1].Type }; - } - else - { - typeArgs = new[] { elementType, args[0].Type }; - } + throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresOneArg, methodName); } - else if (methodName == "SelectMany") + + typeArgs = new[] { ResolveTypeFromArgumentExpression(methodName, args[0]) }; + args = new Expression[0]; + } + else if (new[] { "Min", "Max", "Select", "OrderBy", "OrderByDescending", "ThenBy", "ThenByDescending", "GroupBy" }.Contains(methodName)) + { + if (args.Length == 2) { - var bodyType = Expression.Lambda(args[0], innerIt).Body.Type; - var interfaces = bodyType.GetInterfaces().Union(new[] { bodyType }); - Type interfaceType = interfaces.Single(i => i.Name == typeof(IEnumerable<>).Name); - Type resultType = interfaceType.GetTypeInfo().GetGenericTypeArguments()[0]; - typeArgs = new[] { elementType, resultType }; + typeArgs = new[] { elementType, args[0].Type, args[1].Type }; } else { - typeArgs = new[] { elementType }; + typeArgs = new[] { elementType, args[0].Type }; } + } + else if (methodName == "SelectMany") + { + var bodyType = Expression.Lambda(args[0], innerIt).Body.Type; + var interfaces = bodyType.GetInterfaces().Union(new[] { bodyType }); + Type interfaceType = interfaces.Single(i => i.Name == typeof(IEnumerable<>).Name); + Type resultType = interfaceType.GetTypeInfo().GetGenericTypeArguments()[0]; + typeArgs = new[] { elementType, resultType }; + } + else + { + typeArgs = new[] { elementType }; + } - if (args.Length == 0) + if (args.Length == 0) + { + args = new[] { instance }; + } + else + { + if (new[] { "Concat", "Contains", "DefaultIfEmpty", "Except", "Intersect", "Skip", "Take", "Union" }.Contains(methodName)) { - args = new[] { instance }; + args = new[] { instance, args[0] }; } else { - if (new[] { "Concat", "Contains", "DefaultIfEmpty", "Except", "Intersect", "Skip", "Take", "Union" }.Contains(methodName)) + if (args.Length == 2) { - args = new[] { instance, args[0] }; + args = new[] { instance, Expression.Lambda(args[0], innerIt), Expression.Lambda(args[1], innerIt) }; } else { - if (args.Length == 2) - { - args = new[] { instance, Expression.Lambda(args[0], innerIt), Expression.Lambda(args[1], innerIt) }; - } - else - { - args = new[] { instance, Expression.Lambda(args[0], innerIt) }; - } + args = new[] { instance, Expression.Lambda(args[0], innerIt) }; } } - - return Expression.Call(callType, methodName, typeArgs, args); } - private Type ResolveTypeFromArgumentExpression(string functionName, Expression argumentExpression, int? arguments = null) + return Expression.Call(callType, methodName, typeArgs, args); + } + + private Type ResolveTypeFromArgumentExpression(string functionName, Expression argumentExpression, int? arguments = null) + { + string argument = arguments == null ? string.Empty : arguments == 1 ? "first " : "second "; + switch (argumentExpression) { - string argument = arguments == null ? string.Empty : arguments == 1 ? "first " : "second "; - switch (argumentExpression) - { - case ConstantExpression constantExpression: - switch (constantExpression.Value) - { - case string typeName: - return ResolveTypeStringFromArgument(typeName); + case ConstantExpression constantExpression: + switch (constantExpression.Value) + { + case string typeName: + return ResolveTypeStringFromArgument(typeName); - case Type type: - return type; + case Type type: + return type; - default: - throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresNotNullArgOfType, functionName, argument, "string or System.Type"); - } + default: + throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresNotNullArgOfType, functionName, argument, "string or System.Type"); + } - default: - throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresNotNullArgOfType, functionName, argument, "ConstantExpression"); - } + default: + throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresNotNullArgOfType, functionName, argument, "ConstantExpression"); } + } - private Type ResolveTypeStringFromArgument(string typeName) + private Type ResolveTypeStringFromArgument(string typeName) + { + bool typeIsNullable = false; + if (typeName.EndsWith("?")) { - bool typeIsNullable = false; - if (typeName.EndsWith("?")) - { - typeName = typeName.TrimEnd('?'); - typeIsNullable = true; - } - - var resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); - if (resultType == null) - { - throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, typeName); - } - - return typeIsNullable ? TypeHelper.ToNullableType(resultType) : resultType; + typeName = typeName.TrimEnd('?'); + typeIsNullable = true; } - private Expression[] ParseArgumentList() + var resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); + if (resultType == null) { - _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); - _textParser.NextToken(); - Expression[] args = _textParser.CurrentToken.Id != TokenId.CloseParen ? ParseArguments() : new Expression[0]; - _textParser.ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); - _textParser.NextToken(); - return args; + throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, typeName); } - private Expression[] ParseArguments() - { - var argList = new List(); - while (true) - { - var argumentExpression = ParseConditionalOperator(); + return typeIsNullable ? TypeHelper.ToNullableType(resultType) : resultType; + } + + private Expression[] ParseArgumentList() + { + _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); + _textParser.NextToken(); + Expression[] args = _textParser.CurrentToken.Id != TokenId.CloseParen ? ParseArguments() : new Expression[0]; + _textParser.ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); + _textParser.NextToken(); + return args; + } - _expressionHelper.WrapConstantExpression(ref argumentExpression); + private Expression[] ParseArguments() + { + var argList = new List(); + while (true) + { + var argumentExpression = ParseConditionalOperator(); - argList.Add(argumentExpression); + _expressionHelper.WrapConstantExpression(ref argumentExpression); - if (_textParser.CurrentToken.Id != TokenId.Comma) - { - break; - } + argList.Add(argumentExpression); - _textParser.NextToken(); + if (_textParser.CurrentToken.Id != TokenId.Comma) + { + break; } - return argList.ToArray(); - } - - private Expression ParseElementAccess(Expression expr) - { - int errorPos = _textParser.CurrentToken.Pos; - _textParser.ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected); _textParser.NextToken(); + } - Expression[] args = ParseArguments(); - _textParser.ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected); - _textParser.NextToken(); + return argList.ToArray(); + } - if (expr.Type.IsArray) - { - if (expr.Type.GetArrayRank() != 1 || args.Length != 1) - { - throw ParseError(errorPos, Res.CannotIndexMultiDimArray); - } + private Expression ParseElementAccess(Expression expr) + { + int errorPos = _textParser.CurrentToken.Pos; + _textParser.ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected); + _textParser.NextToken(); - var indexExpression = _parsingConfig.ExpressionPromoter.Promote(args[0], typeof(int), true, false); - if (indexExpression == null) - { - throw ParseError(errorPos, Res.InvalidIndex); - } + Expression[] args = ParseArguments(); + _textParser.ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected); + _textParser.NextToken(); - return Expression.ArrayIndex(expr, indexExpression); + if (expr.Type.IsArray) + { + if (expr.Type.GetArrayRank() != 1 || args.Length != 1) + { + throw ParseError(errorPos, Res.CannotIndexMultiDimArray); } - switch (_methodFinder.FindIndexer(expr.Type, args, out var mb)) + var indexExpression = _parsingConfig.ExpressionPromoter.Promote(args[0], typeof(int), true, false); + if (indexExpression == null) { - case 0: - throw ParseError(errorPos, Res.NoApplicableIndexer, - TypeHelper.GetTypeName(expr.Type)); - - case 1: - var indexMethod = (MethodInfo)mb!; - var indexParameterType = indexMethod.GetParameters().First().ParameterType; - - var indexArgumentExpression = args[0]; // Indexer only has 1 parameter, so we can use args[0] here - if (indexParameterType != indexArgumentExpression.Type) - { - indexArgumentExpression = Expression.Convert(indexArgumentExpression, indexParameterType); - } - - return Expression.Call(expr, indexMethod, indexArgumentExpression); - - default: - throw ParseError(errorPos, Res.AmbiguousIndexerInvocation, TypeHelper.GetTypeName(expr.Type)); + throw ParseError(errorPos, Res.InvalidIndex); } + + return Expression.ArrayIndex(expr, indexExpression); } - internal static Type ToNullableType(Type type) + switch (_methodFinder.FindIndexer(expr.Type, args, out var mb)) { - Check.NotNull(type, nameof(type)); + case 0: + throw ParseError(errorPos, Res.NoApplicableIndexer, + TypeHelper.GetTypeName(expr.Type)); - if (!type.GetTypeInfo().IsValueType || TypeHelper.IsNullableType(type)) - { - throw ParseError(-1, Res.TypeHasNoNullableForm, TypeHelper.GetTypeName(type)); - } + case 1: + var indexMethod = (MethodInfo)mb!; + var indexParameterType = indexMethod.GetParameters().First().ParameterType; + + var indexArgumentExpression = args[0]; // Indexer only has 1 parameter, so we can use args[0] here + if (indexParameterType != indexArgumentExpression.Type) + { + indexArgumentExpression = Expression.Convert(indexArgumentExpression, indexParameterType); + } - return typeof(Nullable<>).MakeGenericType(type); + return Expression.Call(expr, indexMethod, indexArgumentExpression); + + default: + throw ParseError(errorPos, Res.AmbiguousIndexerInvocation, TypeHelper.GetTypeName(expr.Type)); } + } - private static bool TryGetMemberName(Expression expression, out string? memberName) + internal static Type ToNullableType(Type type) + { + Check.NotNull(type, nameof(type)); + + if (!type.GetTypeInfo().IsValueType || TypeHelper.IsNullableType(type)) { - var memberExpression = expression as MemberExpression; - if (memberExpression == null && expression.NodeType == ExpressionType.Coalesce) - { - memberExpression = (expression as BinaryExpression)?.Left as MemberExpression; - } + throw ParseError(-1, Res.TypeHasNoNullableForm, TypeHelper.GetTypeName(type)); + } - if (memberExpression != null) - { - memberName = memberExpression.Member.Name; - return true; - } + return typeof(Nullable<>).MakeGenericType(type); + } -#if NETFX_CORE - var indexExpression = expression as IndexExpression; - if (indexExpression != null && indexExpression.Indexer.DeclaringType == typeof(DynamicObjectClass)) - { - memberName = ((ConstantExpression)indexExpression.Arguments.First()).Value as string; - return true; - } -#endif - memberName = null; - return false; + private static bool TryGetMemberName(Expression expression, out string? memberName) + { + var memberExpression = expression as MemberExpression; + if (memberExpression == null && expression.NodeType == ExpressionType.Coalesce) + { + memberExpression = (expression as BinaryExpression)?.Left as MemberExpression; } - private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) + if (memberExpression != null) { - Expression[] args = { expr }; - - if (!_methodFinder.ContainsMethod(signatures, "F", false, null, ref args)) - { - throw IncompatibleOperandError(opName, expr, errorPos); - } + memberName = memberExpression.Member.Name; + return true; + } - expr = args[0]; +#if NETFX_CORE + var indexExpression = expression as IndexExpression; + if (indexExpression != null && indexExpression.Indexer.DeclaringType == typeof(DynamicObjectClass)) + { + memberName = ((ConstantExpression)indexExpression.Arguments.First()).Value as string; + return true; } +#endif + memberName = null; + return false; + } - private static string? GetOverloadedOperationName(TokenId tokenId) + private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) + { + Expression[] args = { expr }; + + if (!_methodFinder.ContainsMethod(signatures, "F", false, null, ref args)) { - switch (tokenId) - { - case TokenId.DoubleEqual: - case TokenId.Equal: - return "op_Equality"; - case TokenId.ExclamationEqual: - return "op_Inequality"; - default: - return null; - } + throw IncompatibleOperandError(opName, expr, errorPos); } - private void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref Expression left, ref Expression right, int errorPos) + expr = args[0]; + } + + private static string? GetOverloadedOperationName(TokenId tokenId) + { + switch (tokenId) { - Expression[] args = { left, right }; + case TokenId.DoubleEqual: + case TokenId.Equal: + return "op_Equality"; + case TokenId.ExclamationEqual: + return "op_Inequality"; + default: + return null; + } + } - // support operator overloading - var nativeOperation = GetOverloadedOperationName(opId); - bool found = false; + private void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref Expression left, ref Expression right, int errorPos) + { + Expression[] args = { left, right }; - if (nativeOperation != null) - { - // first try left operand's equality operators - found = _methodFinder.ContainsMethod(left.Type, nativeOperation, true, null, ref args); - if (!found) - { - found = _methodFinder.ContainsMethod(right.Type, nativeOperation, true, null, ref args); - } - } + // support operator overloading + var nativeOperation = GetOverloadedOperationName(opId); + bool found = false; - if (!found && !_methodFinder.ContainsMethod(signatures, "F", false, null, ref args)) + if (nativeOperation != null) + { + // first try left operand's equality operators + found = _methodFinder.ContainsMethod(left.Type, nativeOperation, true, null, ref args); + if (!found) { - throw IncompatibleOperandsError(opName, left, right, errorPos); + found = _methodFinder.ContainsMethod(right.Type, nativeOperation, true, null, ref args); } - - left = args[0]; - right = args[1]; } - private static Exception IncompatibleOperandError(string opName, Expression expr, int errorPos) + if (!found && !_methodFinder.ContainsMethod(signatures, "F", false, null, ref args)) { - return ParseError(errorPos, Res.IncompatibleOperand, opName, TypeHelper.GetTypeName(expr.Type)); + throw IncompatibleOperandsError(opName, left, right, errorPos); } - private static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int errorPos) - { - return ParseError(errorPos, Res.IncompatibleOperands, opName, TypeHelper.GetTypeName(left.Type), TypeHelper.GetTypeName(right.Type)); - } + left = args[0]; + right = args[1]; + } - private MemberInfo? FindPropertyOrField(Type type, string memberName, bool staticAccess) - { -#if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) - var extraBindingFlag = _parsingConfig.PrioritizePropertyOrFieldOverTheType && staticAccess ? BindingFlags.Static : BindingFlags.Instance; - var bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly | extraBindingFlag; - foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) - { - var findMembersType = _parsingConfig?.IsCaseSensitive == true ? Type.FilterName : Type.FilterNameIgnoreCase; - var members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, bindingFlags, findMembersType, memberName); + private static Exception IncompatibleOperandError(string opName, Expression expr, int errorPos) + { + return ParseError(errorPos, Res.IncompatibleOperand, opName, TypeHelper.GetTypeName(expr.Type)); + } - if (members.Length != 0) - { - return members[0]; - } - } - return null; -#else - var isCaseSensitive = _parsingConfig?.IsCaseSensitive == true; - foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) - { - // Try to find a property with the specified memberName - MemberInfo? member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); - if (member != null) - { - return member; - } + private static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int errorPos) + { + return ParseError(errorPos, Res.IncompatibleOperands, opName, TypeHelper.GetTypeName(left.Type), TypeHelper.GetTypeName(right.Type)); + } - // If no property is found, try to get a field with the specified memberName - member = t.GetTypeInfo().DeclaredFields.FirstOrDefault(x => (!staticAccess || x.IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); - if (member != null) - { - return member; - } + private MemberInfo? FindPropertyOrField(Type type, string memberName, bool staticAccess) + { +#if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) + var extraBindingFlag = _parsingConfig.PrioritizePropertyOrFieldOverTheType && staticAccess ? BindingFlags.Static : BindingFlags.Instance; + var bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly | extraBindingFlag; + foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) + { + var findMembersType = _parsingConfig?.IsCaseSensitive == true ? Type.FilterName : Type.FilterNameIgnoreCase; + var members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, bindingFlags, findMembersType, memberName); - // No property or field is found, try the base type. + if (members.Length != 0) + { + return members[0]; } - return null; -#endif } - - private bool TokenIdentifierIs(string id) + return null; +#else + var isCaseSensitive = _parsingConfig?.IsCaseSensitive == true; + foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { - return _textParser.CurrentToken.Id == TokenId.Identifier && string.Equals(id, _textParser.CurrentToken.Text, StringComparison.OrdinalIgnoreCase); - } + // Try to find a property with the specified memberName + MemberInfo? member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); + if (member != null) + { + return member; + } - private string GetIdentifier() - { - _textParser.ValidateToken(TokenId.Identifier, Res.IdentifierExpected); - string id = _textParser.CurrentToken.Text; - if (id.Length > 1 && id[0] == '@') + // If no property is found, try to get a field with the specified memberName + member = t.GetTypeInfo().DeclaredFields.FirstOrDefault(x => (!staticAccess || x.IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); + if (member != null) { - id = id.Substring(1); + return member; } - return id; + // No property or field is found, try the base type. } + return null; +#endif + } - private Exception ParseError(string format, params object[] args) - { - return ParseError(_textParser.CurrentToken.Pos, format, args); - } + private bool TokenIdentifierIs(string id) + { + return _textParser.CurrentToken.Id == TokenId.Identifier && string.Equals(id, _textParser.CurrentToken.Text, StringComparison.OrdinalIgnoreCase); + } - private static Exception ParseError(int pos, string format, params object[] args) + private string GetIdentifier() + { + _textParser.ValidateToken(TokenId.Identifier, Res.IdentifierExpected); + string id = _textParser.CurrentToken.Text; + if (id.Length > 1 && id[0] == '@') { - return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos); + id = id.Substring(1); } + + return id; + } + + private Exception ParseError(string format, params object[] args) + { + return ParseError(_textParser.CurrentToken.Pos, format, args); + } + + private static Exception ParseError(int pos, string format, params object[] args) + { + return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos); } } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs b/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs index 42acec1d..e2cb4904 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs @@ -1,9 +1,11 @@ -using System.Linq.Expressions; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal interface IConstantExpressionWrapper { - internal interface IConstantExpressionWrapper - { - void Wrap(ref Expression expression); - } -} + void Wrap(ref Expression expression); + + bool TryUnwrap(MemberExpression? expression, [NotNullWhen(true)] out TValue? value); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs index 8fb14e71..b276a712 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs @@ -1,43 +1,45 @@ -using System.Linq.Expressions; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal interface IExpressionHelper { - internal interface IExpressionHelper - { - void ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref Expression left, ref Expression right); + void ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref Expression left, ref Expression right); + + Expression GenerateAdd(Expression left, Expression right); - Expression GenerateAdd(Expression left, Expression right); + Expression GenerateEqual(Expression left, Expression right); - Expression GenerateEqual(Expression left, Expression right); + Expression GenerateGreaterThan(Expression left, Expression right); - Expression GenerateGreaterThan(Expression left, Expression right); + Expression GenerateGreaterThanEqual(Expression left, Expression right); - Expression GenerateGreaterThanEqual(Expression left, Expression right); + Expression GenerateLessThan(Expression left, Expression right); - Expression GenerateLessThan(Expression left, Expression right); + Expression GenerateLessThanEqual(Expression left, Expression right); - Expression GenerateLessThanEqual(Expression left, Expression right); + Expression GenerateNotEqual(Expression left, Expression right); - Expression GenerateNotEqual(Expression left, Expression right); + Expression GenerateStringConcat(Expression left, Expression right); - Expression GenerateStringConcat(Expression left, Expression right); + Expression GenerateSubtract(Expression left, Expression right); - Expression GenerateSubtract(Expression left, Expression right); + void OptimizeForEqualityIfPossible(ref Expression left, ref Expression right); - void OptimizeForEqualityIfPossible(ref Expression left, ref Expression right); + Expression? OptimizeStringForEqualityIfPossible(string text, Type type); - Expression? OptimizeStringForEqualityIfPossible(string text, Type type); + bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, bool addSelf, out Expression generatedExpression); - bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, bool addSelf, out Expression generatedExpression); + bool ExpressionQualifiesForNullPropagation(Expression expression); - bool ExpressionQualifiesForNullPropagation(Expression expression); + void WrapConstantExpression(ref Expression argument); - void WrapConstantExpression(ref Expression argument); + bool TryUnwrapConstantExpression(Expression? expression, [NotNullWhen(true)] out TValue? value); - bool MemberExpressionIsDynamic(Expression expression); + bool MemberExpressionIsDynamic(Expression expression); - Expression ConvertToExpandoObjectAndCreateDynamicExpression(Expression expression, Type type, string propertyName); + Expression ConvertToExpandoObjectAndCreateDynamicExpression(Expression expression, Type type, string propertyName); - Expression GenerateDefaultExpression(Type type); - } -} + Expression GenerateDefaultExpression(Type type); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IEqualitySignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IEqualitySignatures.cs index 8b379b53..e7c79c31 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IEqualitySignatures.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IEqualitySignatures.cs @@ -1,23 +1,22 @@ -namespace System.Linq.Dynamic.Core.Parser.SupportedOperands +namespace System.Linq.Dynamic.Core.Parser.SupportedOperands; + +internal interface IEqualitySignatures : IRelationalSignatures { - internal interface IEqualitySignatures : IRelationalSignatures - { - void F(bool x, bool y); - void F(bool? x, bool? y); + void F(bool x, bool y); + void F(bool? x, bool? y); - // Disabled 4 lines below because of : https://github.com/StefH/System.Linq.Dynamic.Core/issues/19 - //void F(DateTime x, string y); - //void F(DateTime? x, string y); - //void F(string x, DateTime y); - //void F(string x, DateTime? y); + // Disabled 4 lines below because of : https://github.com/StefH/System.Linq.Dynamic.Core/issues/19 + //void F(DateTime x, string y); + //void F(DateTime? x, string y); + //void F(string x, DateTime y); + //void F(string x, DateTime? y); - void F(Guid x, Guid y); - void F(Guid? x, Guid? y); + void F(Guid x, Guid y); + void F(Guid? x, Guid? y); - // Disabled 4 lines below because of : https://github.com/StefH/System.Linq.Dynamic.Core/pull/200 - //void F(Guid x, string y); - //void F(Guid? x, string y); - //void F(string x, Guid y); - //void F(string x, Guid? y); - } -} + // Disabled 4 lines below because of : https://github.com/StefH/System.Linq.Dynamic.Core/pull/200 + //void F(Guid x, string y); + //void F(Guid? x, string y); + //void F(string x, Guid y); + //void F(string x, Guid? y); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs b/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs index 34a923e5..3121f4af 100644 --- a/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs +++ b/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs @@ -1,12 +1,11 @@ -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal class WrappedValue { - internal class WrappedValue - { - public TValue Value { get; private set; } + public TValue Value { get; } - public WrappedValue(TValue value) - { - Value = value; - } + public WrappedValue(TValue value) + { + Value = value; } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs new file mode 100644 index 00000000..698e63fe --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using FluentAssertions; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests; + +public partial class QueryableTests +{ + /// + /// Issue #645 + /// + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValue_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Terri Lee Duffy", + CompanyName = "ABC", + City = "Paris", + Phone = "333-444444", + Location = new Location { Name = "test" }, + LastContact = DateTimeOffset.Parse("2022-11-14") + }, + new() + { + Name = "Garry Moore", + CompanyName = "ABC", + City = "Paris", + Phone = "54654-444444", + Location = new Location { Name = "other test", UpdateAt = DateTimeOffset.Parse("2022-11-16") }, + LastContact = DateTimeOffset.Parse("2022-11-16") + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act 1A + var result1A = list.AsQueryable().Where(config, "LastContact = \"2022-11-16\"").ToArray(); + + // Assert 1A + result1A.Should().HaveCount(1); + + // Act 1B + var result1B = list.AsQueryable().Where(config, "\"2022-11-16\" == LastContact").ToArray(); + + // Assert 1B + result1B.Should().HaveCount(1); + + // Act 2A + var result2A = list.AsQueryable().Where("Location.UpdateAt = \"2022-11-16\"").ToArray(); + + // Assert 2A + result2A.Should().HaveCount(1); + + // Act 2B + var result2B = list.AsQueryable().Where("\"2022-11-16\" == Location.UpdateAt").ToArray(); + + // Assert 2B + result2B.Should().HaveCount(1); + } +} + +public class Customer +{ + public int CustomerID { get; set; } + public string Name { get; set; } + public string CompanyName { get; set; } + public string City { get; set; } + public string Phone { get; set; } + public Location Location { get; set; } + public DateTimeOffset? LastContact { get; set; } +} + +public class Location +{ + public int LocationID { get; set; } + public string Name { get; set; } + public DateTimeOffset UpdateAt { get; set; } +} \ No newline at end of file From f5676b0b4e7ed6a8c78bd2943e438cc0bbf91e14 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 5 Feb 2023 16:47:35 +0100 Subject: [PATCH 029/214] v1.2.25 --- CHANGELOG.md | 7 +++++++ Generate-ReleaseNotes.bat | 2 +- version.xml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dbab80c..f02fb429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v1.2.25 (05 February 2023) +- [#664](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/664) - Add config setting for PrioritizePropertyOrFieldOverTheType [feature] contributed by [StefH](https://github.com/StefH) +- [#665](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/665) - Update AbstractDynamicLinqCustomTypeProvider to exclude null types [bug] contributed by [StefH](https://github.com/StefH) +- [#666](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/666) - Fixed ExpressionParser when WrappedValue-string is used for equals-operator contributed by [StefH](https://github.com/StefH) +- [#645](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/645) - With UseParameterizedNamesInDynamicQuery, can't compare DateTimeOffset with String [bug] +- [#662](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/662) - System.Linq.Dynamic.Core.Exceptions.ParseException : No applicable method 'DateTime' exists in type [feature] + # v1.2.24 (18 December 2022) - [#621](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/621) - Fix Join on inherited class [bug] contributed by [StefH](https://github.com/StefH) - [#646](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/646) - Add more unittests for issue 645 [feature] contributed by [StefH](https://github.com/StefH) diff --git a/Generate-ReleaseNotes.bat b/Generate-ReleaseNotes.bat index a4e98cd5..b370cd6a 100644 --- a/Generate-ReleaseNotes.bat +++ b/Generate-ReleaseNotes.bat @@ -1,5 +1,5 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=v1.2.24 +SET version=v1.2.25 GitHubReleaseNotes --output CHANGELOG.md --exclude-labels invalid question documentation wontfix --language en --version %version% --token %GH_TOKEN% diff --git a/version.xml b/version.xml index 56d94df6..e503a137 100644 --- a/version.xml +++ b/version.xml @@ -1,5 +1,5 @@ - 24 + 25 From 5cf83570b4f6f2d302a6cf669d48c538a78f1967 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 11 Feb 2023 11:49:21 +0100 Subject: [PATCH 030/214] Add support for DateOnly and TimeOnly (#671) * DateOnly * TimeOnly * fix --- .../Parser/ConstantExpressionWrapper.cs | 37 +++++++- .../Parser/ExpressionHelper.cs | 15 ++- .../Parser/ExpressionParser.cs | 21 +++-- .../Parser/PredefinedTypesHelper.cs | 6 +- .../IAddAndSubtractSignatures.cs | 38 ++++++++ .../SupportedOperands/IAddSignatures.cs | 10 -- .../IArithmeticSignatures.cs | 37 ++++---- .../IRelationalSignatures.cs | 45 ++++++--- .../SupportedOperands/ISubtractSignatures.cs | 8 -- .../Parser/TypeHelper.cs | 8 +- .../TypeConverters/CustomDateTimeConverter.cs | 4 + .../TypeConverters/DateOnlyConverter.cs | 47 ++++++++++ .../TypeConverters/TimeOnlyConverter.cs | 47 ++++++++++ .../TypeConverters/TypeConverterFactory.cs | 66 +++++++------ .../ExpressionTests.cs | 47 ++++++++++ .../ExpressionParserTests.TypeAccess.cs | 94 +++++++++++++++++++ 16 files changed, 437 insertions(+), 93 deletions(-) create mode 100644 src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddAndSubtractSignatures.cs delete mode 100644 src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddSignatures.cs delete mode 100644 src/System.Linq.Dynamic.Core/Parser/SupportedOperands/ISubtractSignatures.cs create mode 100644 src/System.Linq.Dynamic.Core/TypeConverters/DateOnlyConverter.cs create mode 100644 src/System.Linq.Dynamic.Core/TypeConverters/TimeOnlyConverter.cs diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs index 201afbf6..39e7a429 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs @@ -151,7 +151,24 @@ public void Wrap(ref Expression expression) { expression = Wrap((TimeSpan?)constantExpression.Value); } - +#if NET6_0_OR_GREATER + else if (constantExpression.Type == typeof(DateOnly)) + { + expression = Wrap((DateOnly)constantExpression.Value); + } + else if (constantExpression.Type == typeof(DateOnly?)) + { + expression = Wrap((DateOnly?)constantExpression.Value); + } + else if (constantExpression.Type == typeof(TimeOnly)) + { + expression = Wrap((TimeOnly)constantExpression.Value); + } + else if (constantExpression.Type == typeof(TimeOnly?)) + { + expression = Wrap((TimeOnly?)constantExpression.Value); + } +#endif return; } @@ -189,6 +206,24 @@ public void Wrap(ref Expression expression) { expression = Wrap(Expression.Lambda>(newExpression).Compile()()); } +#if NET6_0_OR_GREATER + else if (newExpression.Type == typeof(DateOnly)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(DateOnly?)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(TimeOnly)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } + else if (newExpression.Type == typeof(TimeOnly?)) + { + expression = Wrap(Expression.Lambda>(newExpression).Compile()()); + } +#endif } } diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs index 5900e037..75dd8752 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs @@ -207,10 +207,23 @@ public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression ri public Expression? OptimizeStringForEqualityIfPossible(string? text, Type type) { - if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) + if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTime)) { return Expression.Constant(dateTime, typeof(DateTime)); } + +#if NET6_0_OR_GREATER + if (type == typeof(DateOnly) && DateOnly.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateOnly)) + { + return Expression.Constant(dateOnly, typeof(DateOnly)); + } + + if (type == typeof(TimeOnly) && TimeOnly.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out var timeOnly)) + { + return Expression.Constant(timeOnly, typeof(TimeOnly)); + } +#endif + #if !NET35 if (type == typeof(Guid) && Guid.TryParse(text, out Guid guid)) { diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index cb840f6a..22089efe 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -490,19 +490,19 @@ private Expression ParseComparisonOperator() } } } - else if ((constantExpr = right as ConstantExpression) != null && constantExpr.Value is string stringValueR && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null) + else if ((constantExpr = right as ConstantExpression) != null && constantExpr.Value is string stringValueR && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null && typeConverter.CanConvertFrom(right.Type)) { right = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueR), left.Type); } - else if ((constantExpr = left as ConstantExpression) != null && constantExpr.Value is string stringValueL && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null) + else if ((constantExpr = left as ConstantExpression) != null && constantExpr.Value is string stringValueL && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null && typeConverter.CanConvertFrom(left.Type)) { left = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueL), right.Type); } - else if (_expressionHelper.TryUnwrapConstantExpression(right, out var unwrappedStringValueR) && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null) + else if (_expressionHelper.TryUnwrapConstantExpression(right, out var unwrappedStringValueR) && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null && typeConverter.CanConvertFrom(right.Type)) { right = Expression.Constant(typeConverter.ConvertFromInvariantString(unwrappedStringValueR), left.Type); } - else if (_expressionHelper.TryUnwrapConstantExpression(left, out var unwrappedStringValueL) && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null) + else if (_expressionHelper.TryUnwrapConstantExpression(left, out var unwrappedStringValueL) && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null && typeConverter.CanConvertFrom(left.Type)) { left = Expression.Constant(typeConverter.ConvertFromInvariantString(unwrappedStringValueL), right.Type); } @@ -654,10 +654,11 @@ private Expression ParseShiftOperator() private Expression ParseAdditive() { Expression left = ParseMultiplicative(); - while (_textParser.CurrentToken.Id == TokenId.Plus || _textParser.CurrentToken.Id == TokenId.Minus) + while (_textParser.CurrentToken.Id is TokenId.Plus or TokenId.Minus) { Token op = _textParser.CurrentToken; _textParser.NextToken(); + Expression right = ParseMultiplicative(); switch (op.Id) { @@ -668,12 +669,13 @@ private Expression ParseAdditive() } else { - CheckAndPromoteOperands(typeof(IAddSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + CheckAndPromoteOperands(typeof(IAddAndSubtractSignatures), op.Id, op.Text, ref left, ref right, op.Pos); left = _expressionHelper.GenerateAdd(left, right); } break; + case TokenId.Minus: - CheckAndPromoteOperands(typeof(ISubtractSignatures), op.Id, op.Text, ref left, ref right, op.Pos); + CheckAndPromoteOperands(typeof(IAddAndSubtractSignatures), op.Id, op.Text, ref left, ref right, op.Pos); left = _expressionHelper.GenerateSubtract(left, right); break; } @@ -685,8 +687,7 @@ private Expression ParseAdditive() private Expression ParseMultiplicative() { Expression left = ParseUnary(); - while (_textParser.CurrentToken.Id == TokenId.Asterisk || _textParser.CurrentToken.Id == TokenId.Slash || - _textParser.CurrentToken.Id == TokenId.Percent || TokenIdentifierIs("mod")) + while (_textParser.CurrentToken.Id is TokenId.Asterisk or TokenId.Slash or TokenId.Percent || TokenIdentifierIs("mod")) { Token op = _textParser.CurrentToken; _textParser.NextToken(); @@ -697,9 +698,11 @@ private Expression ParseMultiplicative() case TokenId.Asterisk: left = Expression.Multiply(left, right); break; + case TokenId.Slash: left = Expression.Divide(left, right); break; + case TokenId.Percent: case TokenId.Identifier: left = Expression.Modulo(left, right); diff --git a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs index d42377a8..3bfe8bb6 100644 --- a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs @@ -44,7 +44,11 @@ internal static class PredefinedTypesHelper { typeof(Guid), 0 }, { typeof(Math), 0 }, { typeof(Convert), 0 }, - { typeof(Uri), 0 } + { typeof(Uri), 0 }, +#if NET6_0_OR_GREATER + { typeof(DateOnly), 0 }, + { typeof(TimeOnly), 0 } +#endif }); static PredefinedTypesHelper() diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddAndSubtractSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddAndSubtractSignatures.cs new file mode 100644 index 00000000..a329e961 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddAndSubtractSignatures.cs @@ -0,0 +1,38 @@ +namespace System.Linq.Dynamic.Core.Parser.SupportedOperands; + +internal interface IAddAndSubtractSignatures : IArithmeticSignatures +{ + void F(TimeSpan x, TimeSpan y); + + void F(TimeSpan x, TimeSpan? y); + + void F(TimeSpan? x, TimeSpan y); + + void F(TimeSpan? x, TimeSpan? y); + + void F(DateTime x, DateTime y); + + void F(DateTime x, DateTime? y); + + void F(DateTime? x, DateTime y); + + void F(DateTime? x, DateTime? y); + +#if NET6_0_OR_GREATER + void F(DateOnly x, DateOnly y); + + void F(DateOnly x, DateOnly? y); + + void F(DateOnly? x, DateOnly y); + + void F(DateOnly? x, DateOnly? y); + + void F(TimeOnly x, TimeOnly y); + + void F(TimeOnly x, TimeOnly? y); + + void F(TimeOnly? x, TimeOnly y); + + void F(TimeOnly? x, TimeOnly? y); +#endif +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddSignatures.cs deleted file mode 100644 index b8b78ae1..00000000 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IAddSignatures.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace System.Linq.Dynamic.Core.Parser.SupportedOperands -{ - internal interface IAddSignatures : IArithmeticSignatures - { - void F(DateTime x, TimeSpan y); - void F(TimeSpan x, TimeSpan y); - void F(DateTime? x, TimeSpan? y); - void F(TimeSpan? x, TimeSpan? y); - } -} diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IArithmeticSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IArithmeticSignatures.cs index 602face9..1021c660 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IArithmeticSignatures.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IArithmeticSignatures.cs @@ -1,20 +1,19 @@ -namespace System.Linq.Dynamic.Core.Parser.SupportedOperands +namespace System.Linq.Dynamic.Core.Parser.SupportedOperands; + +internal interface IArithmeticSignatures { - internal interface IArithmeticSignatures - { - void F(int x, int y); - void F(uint x, uint y); - void F(long x, long y); - void F(ulong x, ulong y); - void F(float x, float y); - void F(double x, double y); - void F(decimal x, decimal y); - void F(int? x, int? y); - void F(uint? x, uint? y); - void F(long? x, long? y); - void F(ulong? x, ulong? y); - void F(float? x, float? y); - void F(double? x, double? y); - void F(decimal? x, decimal? y); - } -} + void F(int x, int y); + void F(uint x, uint y); + void F(long x, long y); + void F(ulong x, ulong y); + void F(float x, float y); + void F(double x, double y); + void F(decimal x, decimal y); + void F(int? x, int? y); + void F(uint? x, uint? y); + void F(long? x, long? y); + void F(ulong? x, ulong? y); + void F(float? x, float? y); + void F(double? x, double? y); + void F(decimal? x, decimal? y); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IRelationalSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IRelationalSignatures.cs index b91855ed..8c1c9c1b 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IRelationalSignatures.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IRelationalSignatures.cs @@ -1,15 +1,32 @@ -namespace System.Linq.Dynamic.Core.Parser.SupportedOperands +namespace System.Linq.Dynamic.Core.Parser.SupportedOperands; + +internal interface IRelationalSignatures : IArithmeticSignatures { - internal interface IRelationalSignatures : IArithmeticSignatures - { - void F(string x, string y); - void F(char x, char y); - void F(DateTime x, DateTime y); - void F(DateTimeOffset x, DateTimeOffset y); - void F(TimeSpan x, TimeSpan y); - void F(char? x, char? y); - void F(DateTime? x, DateTime? y); - void F(DateTimeOffset? x, DateTimeOffset? y); - void F(TimeSpan? x, TimeSpan? y); - } -} + void F(string x, string y); + + void F(char x, char y); + + void F(DateTime x, DateTime y); + + void F(DateTimeOffset x, DateTimeOffset y); + + void F(TimeSpan x, TimeSpan y); + + void F(char? x, char? y); + + void F(DateTime? x, DateTime? y); + + void F(DateTimeOffset? x, DateTimeOffset? y); + + void F(TimeSpan? x, TimeSpan? y); + +#if NET6_0_OR_GREATER + void F(DateOnly x, DateOnly y); + + void F(DateOnly? x, DateOnly? y); + + void F(TimeOnly x, TimeOnly y); + + void F(TimeOnly? x, TimeOnly? y); +#endif +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/ISubtractSignatures.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/ISubtractSignatures.cs deleted file mode 100644 index 19eec926..00000000 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedOperands/ISubtractSignatures.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace System.Linq.Dynamic.Core.Parser.SupportedOperands -{ - internal interface ISubtractSignatures : IAddSignatures - { - void F(DateTime x, DateTime y); - void F(DateTime? x, DateTime? y); - } -} diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index c648bc1f..8ef4bc98 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -279,7 +279,13 @@ public static bool IsStruct(Type type) { if (!nonNullableType.GetTypeInfo().IsPrimitive) { - if (nonNullableType != typeof(decimal) && nonNullableType != typeof(DateTime) && nonNullableType != typeof(Guid)) + if + ( +#if NET6_0_OR_GREATER + nonNullableType != typeof(DateOnly) && nonNullableType != typeof(TimeOnly) && +#endif + nonNullableType != typeof(decimal) && nonNullableType != typeof(DateTime) && nonNullableType != typeof(Guid) + ) { if (!nonNullableType.GetTypeInfo().IsEnum) { diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs b/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs index a0b4e954..5a47c55f 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs @@ -13,7 +13,11 @@ internal class CustomDateTimeConverter : DateTimeOffsetConverter /// The object to be converted. /// A that represents the specified object. /// The conversion cannot be performed. +#if NET6_0_OR_GREATER + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) +#else public override object? ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) +#endif { var dateTimeOffset = base.ConvertFrom(context, culture, value) as DateTimeOffset?; diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/DateOnlyConverter.cs b/src/System.Linq.Dynamic.Core/TypeConverters/DateOnlyConverter.cs new file mode 100644 index 00000000..460c7e35 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/TypeConverters/DateOnlyConverter.cs @@ -0,0 +1,47 @@ +#if NET6_0 +using System.ComponentModel; +using System.Globalization; + +namespace System.Linq.Dynamic.Core.TypeConverters; + +/// +/// Based on https://github.com/dotnet/runtime/issues/68743 +/// +internal class DateOnlyConverter : TypeConverter +{ + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) + { + return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + } + + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + if (value is string s) + { + return DateOnly.Parse(s, culture); + } + + return base.ConvertFrom(context, culture, value); + } + + public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) + { + if (destinationType == typeof(string)) + { + return ((DateOnly?)value)?.ToString(culture); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool IsValid(ITypeDescriptorContext? context, object? value) + { + return value is DateOnly || base.IsValid(context, value); + } +} +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/TimeOnlyConverter.cs b/src/System.Linq.Dynamic.Core/TypeConverters/TimeOnlyConverter.cs new file mode 100644 index 00000000..1cd8df1b --- /dev/null +++ b/src/System.Linq.Dynamic.Core/TypeConverters/TimeOnlyConverter.cs @@ -0,0 +1,47 @@ +#if NET6_0 +using System.ComponentModel; +using System.Globalization; + +namespace System.Linq.Dynamic.Core.TypeConverters; + +/// +/// Based on https://github.com/dotnet/runtime/issues/68743 +/// +internal class TimeOnlyConverter : TypeConverter +{ + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) + { + return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + } + + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + if (value is string s) + { + return TimeOnly.Parse(s, culture); + } + + return base.ConvertFrom(context, culture, value); + } + + public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) + { + if (destinationType == typeof(string)) + { + return ((TimeOnly?)value)?.ToString(culture); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool IsValid(ITypeDescriptorContext? context, object? value) + { + return value is TimeOnly || base.IsValid(context, value); + } +} +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs index d6a4bc92..4115669c 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs @@ -2,49 +2,57 @@ using System.Linq.Dynamic.Core.Parser; using System.Linq.Dynamic.Core.Validation; -namespace System.Linq.Dynamic.Core.TypeConverters +namespace System.Linq.Dynamic.Core.TypeConverters; + +internal class TypeConverterFactory : ITypeConverterFactory { - internal class TypeConverterFactory : ITypeConverterFactory + private readonly ParsingConfig _config; + +#if NET6_0 + static TypeConverterFactory() { - private readonly ParsingConfig _config; + TypeDescriptor.AddAttributes(typeof(DateOnly), new TypeConverterAttribute(typeof(DateOnlyConverter))); + TypeDescriptor.AddAttributes(typeof(TimeOnly), new TypeConverterAttribute(typeof(TimeOnlyConverter))); + } +#endif + + public TypeConverterFactory(ParsingConfig config) + { + _config = Check.NotNull(config); + } - public TypeConverterFactory(ParsingConfig config) + /// + public TypeConverter GetConverter(Type type) + { + Check.NotNull(type); + + if (_config.DateTimeIsParsedAsUTC && (type == typeof(DateTime) || type == typeof(DateTime?))) { - _config = Check.NotNull(config); + return new CustomDateTimeConverter(); } - /// - public TypeConverter GetConverter(Type type) + var typeToCheck = TypeHelper.IsNullableType(type) ? TypeHelper.GetNonNullableType(type) : type; + if (_config.TypeConverters != null && _config.TypeConverters.TryGetValue(typeToCheck, out var typeConverter)) { - Check.NotNull(type); - - if (_config.DateTimeIsParsedAsUTC && (type == typeof(DateTime) || type == typeof(DateTime?))) - { - return new CustomDateTimeConverter(); - } - - var typeToCheck = TypeHelper.IsNullableType(type) ? TypeHelper.GetNonNullableType(type) : type; - if (_config.TypeConverters != null && _config.TypeConverters.TryGetValue(typeToCheck, out var typeConverter)) - { - return typeConverter; - } + return typeConverter; + } #if !SILVERLIGHT - return TypeDescriptor.GetConverter(type); + var c = TypeDescriptor.GetConverter(type); + return c; #else - var attributes = type.GetCustomAttributes(typeof(TypeConverterAttribute), false); + var attributes = type.GetCustomAttributes(typeof(TypeConverterAttribute), false); - if (attributes.Length != 1) - return new TypeConverter(); + if (attributes.Length != 1) + return new TypeConverter(); - var converterAttribute = (TypeConverterAttribute)attributes[0]; - var converterType = Type.GetType(converterAttribute.ConverterTypeName); + var converterAttribute = (TypeConverterAttribute)attributes[0]; + var converterType = Type.GetType(converterAttribute.ConverterTypeName); - if (converterType == null) - return new TypeConverter(); + if (converterType == null) + return new TypeConverter(); - return Activator.CreateInstance(converterType) as TypeConverter; + return Activator.CreateInstance(converterType) as TypeConverter; #endif - } } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index b9b8341a..f951d6e3 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -623,6 +623,53 @@ public void ExpressionTests_DateTimeString() Assert.Equal(lst[0], result2.Single()); } +#if NET6_0_OR_GREATER + [Fact] + public void ExpressionTests_DateOnlyString() + { + // Arrange + var now = new DateTime(2023, 2, 10, 12, 13, 14); + var lst = new List + { + DateOnly.FromDateTime(now), + DateOnly.FromDateTime(now.AddDays(1)), + DateOnly.FromDateTime(now.AddDays(2)) + }; + var qry = lst.AsQueryable(); + + // Act + var testValue = lst[0].ToString(CultureInfo.InvariantCulture); + var result1 = qry.Where("it = @0", testValue); + var result2 = qry.Where("@0 = it", testValue); + + // Assert + Assert.Equal(lst[0], result1.Single()); + Assert.Equal(lst[0], result2.Single()); + } + + [Fact] + public void ExpressionTests_TimeOnlyString() + { + // Arrange + var now = new DateTime(2023, 2, 10, 12, 13, 14); + var lst = new List + { + TimeOnly.FromDateTime(now), + TimeOnly.FromDateTime(now.AddSeconds(1)), + TimeOnly.FromDateTime(now.AddSeconds(2)) + }; + var qry = lst.AsQueryable(); + + // Act + var testValue = "12:13:14"; + var result1 = qry.Where("it = @0", testValue); + var result2 = qry.Where("@0 = it", testValue); + + // Assert + Assert.Equal(lst[0], result1.Single()); + Assert.Equal(lst[0], result2.Single()); + } +#endif [Fact] public void ExpressionTests_DecimalQualifiers() { diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs index d79ca134..0129e36e 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs @@ -84,6 +84,100 @@ public void ParseTypeAccess_Via_Constructor_Any_To_DateTime_Invalid(object any) a.Should().Throw(); } +#if NET6_0_OR_GREATER + [Fact] + public void ParseTypeAccess_Via_Constructor_String_To_DateOnly_Valid() + { + // Arrange + string str = "\"2020-10-31\""; + var parameter = Expression.Parameter(typeof(DateOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({str})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_Arguments_To_DateOnly_Valid() + { + // Arrange + var arguments = "2022, 10, 31"; + var parameter = Expression.Parameter(typeof(DateOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({arguments})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Theory] + [InlineData(null)] + [InlineData("\"abc\"")] + public void ParseTypeAccess_Via_Constructor_Any_To_DateOnly_Invalid(object any) + { + // Arrange + var parameter = Expression.Parameter(typeof(DateOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({any})", new object[] { }, ParsingConfig.Default); + Action a = () => parser.Parse(typeof(DateOnly)); + + // Assert + a.Should().Throw(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_String_To_TimeOnly_Valid() + { + // Arrange + string str = "\"09:15:11\""; + var parameter = Expression.Parameter(typeof(TimeOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({str})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(TimeOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_Arguments_To_TimeOnly_Valid() + { + // Arrange + var arguments = "9, 15, 11"; + var parameter = Expression.Parameter(typeof(TimeOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({arguments})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(TimeOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Theory] + [InlineData(null)] + [InlineData("\"abc\"")] + public void ParseTypeAccess_Via_Constructor_Any_To_TimeOnly_Invalid(object any) + { + // Arrange + var parameter = Expression.Parameter(typeof(TimeOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({any})", new object[] { }, ParsingConfig.Default); + Action a = () => parser.Parse(typeof(TimeOnly)); + + // Assert + a.Should().Throw(); + } +#endif + [Fact] public void ParseTypeAccess_Via_Constructor_String_To_Uri() { From c8edded6d84d7d3be55f0eac5e27b05d66c3b2c2 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 14 Feb 2023 16:55:40 +0100 Subject: [PATCH 031/214] Fixed ExpressionParser when WrappedValue-string is used for equals-operator for Enum (#672) * Fixed ExpressionParser when WrappedValue-string is used for equals-operator to compare Enum * . * . * Partial fixed ExpressionParser when WrappedValue-string is used for in-operator and left operand is enum (#668) * Fix * . --------- Co-authored-by: neilbgr --- .../Parser/ConstantExpressionWrapper.cs | 14 +- .../Parser/ExpressionHelper.cs | 38 +++- .../Parser/ExpressionParser.cs | 45 +++- .../Parser/IConstantExpressionWrapper.cs | 4 +- .../Parser/IExpressionHelper.cs | 6 +- .../Parser/WrappedValue.cs | 74 +++++- .../Parser/WrappedValueTests.cs | 88 ++++++++ ...ts.UseParameterizedNamesInDynamicQuery .cs | 213 +++++++++++++++++- 8 files changed, 463 insertions(+), 19 deletions(-) create mode 100644 test/System.Linq.Dynamic.Core.Tests/Parser/WrappedValueTests.cs diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs index 39e7a429..18c6e4ca 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionWrapper.cs @@ -227,7 +227,7 @@ public void Wrap(ref Expression expression) } } - public bool TryUnwrap(MemberExpression? expression, [NotNullWhen(true)] out TValue? value) + public bool TryUnwrapAsValue(MemberExpression? expression, [NotNullWhen(true)] out TValue? value) { if (expression?.Expression is ConstantExpression { Value: WrappedValue wrapper }) { @@ -239,6 +239,18 @@ public bool TryUnwrap(MemberExpression? expression, [NotNullWhen(true)] return false; } + public bool TryUnwrapAsConstantExpression(MemberExpression? expression, [NotNullWhen(true)] out ConstantExpression? value) + { + if (TryUnwrapAsValue(expression, out var wrappedValue)) + { + value = Expression.Constant(wrappedValue); + return true; + } + + value = default; + return false; + } + private static MemberExpression Wrap(TValue value) { var wrapper = new WrappedValue(value); diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs index 75dd8752..28d08acc 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs @@ -26,9 +26,43 @@ public void WrapConstantExpression(ref Expression argument) } } - public bool TryUnwrapConstantExpression(Expression? expression, [NotNullWhen(true)] out TValue? value) + public bool TryUnwrapAsValue(Expression? expression, [NotNullWhen(true)] out TValue? value) { - if (_parsingConfig.UseParameterizedNamesInDynamicQuery && _constantExpressionWrapper.TryUnwrap(expression as MemberExpression, out value)) + if (_parsingConfig.UseParameterizedNamesInDynamicQuery && _constantExpressionWrapper.TryUnwrapAsValue(expression as MemberExpression, out value)) + { + return true; + } + + value = default; + return false; + } + + public bool TryUnwrapAsConstantExpression(Expression? expression, [NotNullWhen(true)] out ConstantExpression? value) + { + if (_parsingConfig.UseParameterizedNamesInDynamicQuery && _constantExpressionWrapper.TryUnwrapAsConstantExpression(expression as MemberExpression, out value)) + { + return true; + } + + value = default; + return false; + } + + public bool TryUnwrapAsConstantExpression(Expression? expression, [NotNullWhen(true)] out ConstantExpression? value) + { + if (!_parsingConfig.UseParameterizedNamesInDynamicQuery || expression is not MemberExpression memberExpression) + { + value = default; + return false; + } + + if + ( + _constantExpressionWrapper.TryUnwrapAsConstantExpression(memberExpression, out value) || + _constantExpressionWrapper.TryUnwrapAsConstantExpression(memberExpression, out value) || + _constantExpressionWrapper.TryUnwrapAsConstantExpression(memberExpression, out value) || + _constantExpressionWrapper.TryUnwrapAsConstantExpression(memberExpression, out value) + ) { return true; } diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 22089efe..e09049d2 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -313,9 +313,16 @@ private Expression ParseIn() Expression right = ParseUnary(); // if the identifier is an Enum, try to convert the right-side also to an Enum. - if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression constantExpression) + if (left.Type.GetTypeInfo().IsEnum) { - right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpression); + if (right is ConstantExpression constantExprRight) + { + right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExprRight); + } + else if (_expressionHelper.TryUnwrapAsConstantExpression(right, out var unwrappedConstantExprRight)) + { + right = ParseEnumToConstantExpression(op.Pos, left.Type, unwrappedConstantExprRight); + } } // else, check for direct type match @@ -476,13 +483,27 @@ private Expression ParseComparisonOperator() { left = e; } - else if (TypeHelper.IsEnumType(left.Type) && (constantExpr = right as ConstantExpression) != null) + else if (TypeHelper.IsEnumType(left.Type)) { - right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpr); + if (right is ConstantExpression constantExprRight) + { + right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExprRight); + } + else if (_expressionHelper.TryUnwrapAsConstantExpression(right, out var unwrappedConstantExprRight)) + { + right = ParseEnumToConstantExpression(op.Pos, left.Type, unwrappedConstantExprRight); + } } - else if (TypeHelper.IsEnumType(right.Type) && (constantExpr = left as ConstantExpression) != null) + else if (TypeHelper.IsEnumType(right.Type)) { - left = ParseEnumToConstantExpression(op.Pos, right.Type, constantExpr); + if (left is ConstantExpression constantExprLeft) + { + left = ParseEnumToConstantExpression(op.Pos, right.Type, constantExprLeft); + } + else if (_expressionHelper.TryUnwrapAsConstantExpression(left, out var unwrappedConstantExprLeft)) + { + left = ParseEnumToConstantExpression(op.Pos, right.Type, unwrappedConstantExprLeft); + } } else { @@ -498,11 +519,11 @@ private Expression ParseComparisonOperator() { left = Expression.Constant(typeConverter.ConvertFromInvariantString(stringValueL), right.Type); } - else if (_expressionHelper.TryUnwrapConstantExpression(right, out var unwrappedStringValueR) && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null && typeConverter.CanConvertFrom(right.Type)) + else if (_expressionHelper.TryUnwrapAsValue(right, out var unwrappedStringValueR) && (typeConverter = _typeConverterFactory.GetConverter(left.Type)) != null && typeConverter.CanConvertFrom(right.Type)) { right = Expression.Constant(typeConverter.ConvertFromInvariantString(unwrappedStringValueR), left.Type); } - else if (_expressionHelper.TryUnwrapConstantExpression(left, out var unwrappedStringValueL) && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null && typeConverter.CanConvertFrom(left.Type)) + else if (_expressionHelper.TryUnwrapAsValue(left, out var unwrappedStringValueL) && (typeConverter = _typeConverterFactory.GetConverter(right.Type)) != null && typeConverter.CanConvertFrom(left.Type)) { left = Expression.Constant(typeConverter.ConvertFromInvariantString(unwrappedStringValueL), right.Type); } @@ -581,7 +602,7 @@ private Expression ParseComparisonOperator() return left; } - private bool HasImplicitConversion(Type baseType, Type targetType) + private static bool HasImplicitConversion(Type baseType, Type targetType) { var baseTypeHasConversion = baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) @@ -597,12 +618,12 @@ private bool HasImplicitConversion(Type baseType, Type targetType) .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); } - private ConstantExpression ParseEnumToConstantExpression(int pos, Type leftType, ConstantExpression constantExpr) + private static ConstantExpression ParseEnumToConstantExpression(int pos, Type leftType, ConstantExpression constantExpr) { return Expression.Constant(ParseConstantExpressionToEnum(pos, leftType, constantExpr), leftType); } - private object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExpression constantExpr) + private static object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExpression constantExpr) { try { @@ -618,7 +639,7 @@ private object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExp try { - return Enum.ToObject(TypeHelper.GetNonNullableType(leftType), constantExpr.Value); + return Enum.ToObject(TypeHelper.GetNonNullableType(leftType), constantExpr.Value!); } catch { diff --git a/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs b/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs index e2cb4904..93a604c5 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IConstantExpressionWrapper.cs @@ -7,5 +7,7 @@ internal interface IConstantExpressionWrapper { void Wrap(ref Expression expression); - bool TryUnwrap(MemberExpression? expression, [NotNullWhen(true)] out TValue? value); + bool TryUnwrapAsValue(MemberExpression? expression, [NotNullWhen(true)] out TValue? value); + + bool TryUnwrapAsConstantExpression(MemberExpression? expression, [NotNullWhen(true)] out ConstantExpression? value); } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs index b276a712..f78fac30 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs @@ -35,7 +35,11 @@ internal interface IExpressionHelper void WrapConstantExpression(ref Expression argument); - bool TryUnwrapConstantExpression(Expression? expression, [NotNullWhen(true)] out TValue? value); + bool TryUnwrapAsValue(Expression? expression, [NotNullWhen(true)] out TValue? value); + + bool TryUnwrapAsConstantExpression(Expression? expression, [NotNullWhen(true)] out ConstantExpression? value); + + bool TryUnwrapAsConstantExpression(Expression? expression, [NotNullWhen(true)] out ConstantExpression? value); bool MemberExpressionIsDynamic(Expression expression); diff --git a/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs b/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs index 3121f4af..7f107177 100644 --- a/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs +++ b/src/System.Linq.Dynamic.Core/Parser/WrappedValue.cs @@ -1,4 +1,6 @@ -namespace System.Linq.Dynamic.Core.Parser; +using System.Collections.Generic; + +namespace System.Linq.Dynamic.Core.Parser; internal class WrappedValue { @@ -8,4 +10,74 @@ public WrappedValue(TValue value) { Value = value; } + + public static bool operator ==(WrappedValue? left, WrappedValue? right) + { + if (ReferenceEquals(left, right)) + { + return true; + } + + if (ReferenceEquals(left, null) || ReferenceEquals(right, null)) + { + return false; + } + + return EqualityComparer.Default.Equals(left.Value, right.Value); + } + + public static bool operator !=(WrappedValue? left, WrappedValue? right) + { + return !(left == right); + } + + public static bool operator ==(WrappedValue? left, TValue? right) + { + if (ReferenceEquals(left, null)) + { + return false; + } + + return EqualityComparer.Default.Equals(left.Value, right); + } + + public static bool operator !=(WrappedValue? left, TValue? right) + { + return !(left == right); + } + + public static bool operator ==(TValue? left, WrappedValue? right) + { + if (ReferenceEquals(right, null)) + { + return false; + } + + return EqualityComparer.Default.Equals(left, right.Value); + } + + public static bool operator !=(TValue? left, WrappedValue? right) + { + return !(left == right); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj is not WrappedValue other) + { + return false; + } + + return EqualityComparer.Default.Equals(Value, other.Value); + } + + public override int GetHashCode() + { + return Value?.GetHashCode() ?? 0; + } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/WrappedValueTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/WrappedValueTests.cs new file mode 100644 index 00000000..c069cdce --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/WrappedValueTests.cs @@ -0,0 +1,88 @@ +using System.Linq.Dynamic.Core.Parser; +using FluentAssertions; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests.Parser; + +public class WrappedValueTests +{ + [Fact] + public void WrappedValue_OfTypeString_OperatorEquals_String() + { + // Arrange + var wrapped = new WrappedValue("str"); + + // Act + var result1A = wrapped == "str"; + var result1B = "str" == wrapped; + var result2A = wrapped == "x"; + var result2B = "x" == wrapped; + + // Assert + result1A.Should().BeTrue(); + result1B.Should().BeTrue(); + result2A.Should().BeFalse(); + result2B.Should().BeFalse(); + } + + [Fact] + public void WrappedValue_OfTypeString_OperatorNotEquals_String() + { + // Arrange + var wrapped = new WrappedValue("str"); + + // Act + var result1A = wrapped != "str"; + var result1B = "str" != wrapped; + var result2A = wrapped == "x"; + var result2B = "x" == wrapped; + + // Assert + result1A.Should().BeFalse(); + result1B.Should().BeFalse(); + result2A.Should().BeFalse(); + result2B.Should().BeFalse(); + } + + [Fact] + public void WrappedValue_OfTypeString_OperatorEquals_WrappedValue_OfTypeString() + { + // Arrange + var wrapped = new WrappedValue("str"); + var testEqual = new WrappedValue("str"); + var testNotEqual = new WrappedValue("x"); + + // Act + var result1A = wrapped == testEqual; + var result1B = testEqual == wrapped; + var result2A = wrapped == testNotEqual; + var result2B = testNotEqual == wrapped; + + // Assert + result1A.Should().BeTrue(); + result1B.Should().BeTrue(); + result2A.Should().BeFalse(); + result2B.Should().BeFalse(); + } + + [Fact] + public void WrappedValue_OfTypeString_OperatorNotEquals_WrappedValue_OfTypeString() + { + // Arrange + var wrapped = new WrappedValue("str"); + var testEqual = new WrappedValue("str"); + var testNotEqual = new WrappedValue("x"); + + // Act + var result1A = wrapped != testEqual; + var result1B = testEqual != wrapped; + var result2A = wrapped != testNotEqual; + var result2B = testNotEqual != wrapped; + + // Assert + result1A.Should().BeFalse(); + result1B.Should().BeFalse(); + result2A.Should().BeTrue(); + result2B.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs index 698e63fe..c28ba2d2 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.UseParameterizedNamesInDynamicQuery .cs @@ -10,7 +10,7 @@ public partial class QueryableTests /// Issue #645 /// [Fact] - public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValue_Should_Be_Unwrapped() + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValueForDateTime_Should_Be_Unwrapped() { // Arrange var list = new List @@ -64,6 +64,209 @@ public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValue_S // Assert 2B result2B.Should().HaveCount(1); } + + /// + /// Issue #668 + /// + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValueEnum_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Duffy", + GenderType = Gender.Female + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var result = list.AsQueryable().Where(config, "GenderType = \"Female\"").ToArray(); + + // Assert + result.Should().HaveCount(1); + } + + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValueEnumAsParameter_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Duffy", + GenderType = Gender.Female + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var result = list.AsQueryable().Where(config, "GenderType = @0", "Female").ToArray(); + + // Assert + result.Should().HaveCount(1); + } + + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedStringValueEnumArray_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Duffy", + GenderType = Gender.Female + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + }, + new() + { + Name = "Garry", + GenderType = Gender.Other + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var result = list.AsQueryable().Where(config, "GenderType in (\"Female\", \"Other\")").ToArray(); + + // Assert + result.Should().HaveCount(2); + } + + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedIntegerValueEnumArray_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Duffy", + GenderType = Gender.Female + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + }, + new() + { + Name = "Test A", + GenderType = Gender.Other + }, + new() + { + Name = "Test B", + GenderType = Gender.Male + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var result = list.AsQueryable().Where(config, "GenderType in (0, 2)").ToArray(); + + // Assert + result.Should().HaveCount(3); + } + + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedIntegerValueEnum_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Duffy", + GenderType = Gender.Female + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var result = list.AsQueryable().Where(config, "GenderType = 1").ToArray(); + + // Assert + result.Should().HaveCount(1); + } + + [Fact] + public void When_UseParameterizedNamesInDynamicQuery_IsTrue_WrappedIntegerStringValueEnumAsParameter_Should_Be_Unwrapped() + { + // Arrange + var list = new List + { + new() + { + Name = "Duffy", + GenderType = Gender.Female + }, + new() + { + Name = "Garry", + GenderType = Gender.Male + } + }; + + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = true + }; + + // Act + var result = list.AsQueryable().Where(config, "GenderType = @0", 1).ToArray(); + + // Assert + result.Should().HaveCount(1); + } } public class Customer @@ -75,6 +278,7 @@ public class Customer public string Phone { get; set; } public Location Location { get; set; } public DateTimeOffset? LastContact { get; set; } + public Gender GenderType { get; set; } } public class Location @@ -82,4 +286,11 @@ public class Location public int LocationID { get; set; } public string Name { get; set; } public DateTimeOffset UpdateAt { get; set; } +} + +public enum Gender +{ + Male = 0, + Female = 1, + Other = 2 } \ No newline at end of file From 3fb84e971abe5fb4d991a2db5f8ad125d075d062 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 14 Feb 2023 17:08:09 +0100 Subject: [PATCH 032/214] Methods should only be callable on predefined types (#669) * Methods should only be callable on predefined types * add test * ip --- .../IDynamicLinqCustomTypeProvider.cs | 56 +- .../Parser/ExpressionParser.cs | 6 +- .../Parser/PredefinedTypesHelper.cs | 165 +- .../DynamicExpressionParserTests.cs | 2457 +++++++++-------- .../ExpressionTests.MethodCall.cs | 253 ++ .../ExpressionTests.cs | 230 +- .../QueryableTests.Methods.cs | 108 +- .../SecurityTests.cs | 67 + 8 files changed, 1737 insertions(+), 1605 deletions(-) create mode 100644 test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs create mode 100644 test/System.Linq.Dynamic.Core.Tests/SecurityTests.cs diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs index 4d950612..1adc34e9 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs @@ -1,38 +1,36 @@ -using JetBrains.Annotations; -using System.Collections.Generic; +using System.Collections.Generic; using System.Reflection; -namespace System.Linq.Dynamic.Core.CustomTypeProviders +namespace System.Linq.Dynamic.Core.CustomTypeProviders; + +/// +/// Interface for providing functionality to find custom types for or resolve any type. +/// +public interface IDynamicLinqCustomTypeProvider { /// - /// Interface for providing functionality to find custom types for or resolve any type. + /// Returns a list of custom types that System.Linq.Dynamic.Core will understand. /// - public interface IDynamicLinqCustomTypeProvider - { - /// - /// Returns a list of custom types that System.Linq.Dynamic.Core will understand. - /// - /// A list of custom types. - HashSet GetCustomTypes(); + /// A list of custom types. + HashSet GetCustomTypes(); - /// - /// Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand. - /// - /// A list of custom extension methods that System.Linq.Dynamic.Core will understand. - Dictionary> GetExtensionMethods(); + /// + /// Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand. + /// + /// A list of custom extension methods that System.Linq.Dynamic.Core will understand. + Dictionary> GetExtensionMethods(); - /// - /// Resolve any type by fullname which is registered in the current application domain. - /// - /// The typename to resolve. - /// A resolved or null when not found. - Type? ResolveType(string typeName); + /// + /// Resolve any type by fullname which is registered in the current application domain. + /// + /// The typename to resolve. + /// A resolved or null when not found. + Type? ResolveType(string typeName); - /// - /// Resolve any type by the simple name which is registered in the current application domain. - /// - /// The typename to resolve. - /// A resolved or null when not found. - Type? ResolveTypeBySimpleName(string simpleTypeName); - } + /// + /// Resolve any type by the simple name which is registered in the current application domain. + /// + /// The typename to resolve. + /// A resolved or null when not found. + Type? ResolveTypeBySimpleName(string simpleTypeName); } \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index e09049d2..d1ea7a90 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -1696,14 +1696,14 @@ private Expression ParseMemberAccess(Type? type, Expression? expression) } Expression[] args = ParseArgumentList(); - switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out var mb)) + switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out var methodBase)) { case 0: throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type)); case 1: - MethodInfo method = (MethodInfo)mb!; - if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) + var method = (MethodInfo)methodBase!; + if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!)) { throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType!)); } diff --git a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs index 3bfe8bb6..fb19e85f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs @@ -1,108 +1,109 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq.Dynamic.Core.Validation; -using System.Text.RegularExpressions; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal static class PredefinedTypesHelper { - internal static class PredefinedTypesHelper - { - private static readonly string Version = Regex.Match(typeof(PredefinedTypesHelper).AssemblyQualifiedName, @"\d+\.\d+\.\d+\.\d+").ToString(); +#if NETSTANDARD2_0 + private static readonly string Version = Text.RegularExpressions.Regex.Match(typeof(PredefinedTypesHelper).AssemblyQualifiedName!, @"\d+\.\d+\.\d+\.\d+").ToString(); +#endif - // These shorthands have different name than actual type and therefore not recognized by default from the PredefinedTypes. - public static readonly IDictionary PredefinedTypesShorthands = new Dictionary - { - { "int", typeof(int) }, - { "uint", typeof(uint) }, - { "short", typeof(short) }, - { "ushort", typeof(ushort) }, - { "long", typeof(long) }, - { "ulong", typeof(ulong) }, - { "bool", typeof(bool) }, - { "float", typeof(float) } - }; + // These shorthands have different name than actual type and therefore not recognized by default from the PredefinedTypes. + public static readonly IDictionary PredefinedTypesShorthands = new Dictionary + { + { "int", typeof(int) }, + { "uint", typeof(uint) }, + { "short", typeof(short) }, + { "ushort", typeof(ushort) }, + { "long", typeof(long) }, + { "ulong", typeof(ulong) }, + { "bool", typeof(bool) }, + { "float", typeof(float) } + }; - public static readonly IDictionary PredefinedTypes = new ConcurrentDictionary(new Dictionary { - { typeof(object), 0 }, - { typeof(bool), 0 }, - { typeof(char), 0 }, - { typeof(string), 0 }, - { typeof(sbyte), 0 }, - { typeof(byte), 0 }, - { typeof(short), 0 }, - { typeof(ushort), 0 }, - { typeof(int), 0 }, - { typeof(uint), 0 }, - { typeof(long), 0 }, - { typeof(ulong), 0 }, - { typeof(float), 0 }, - { typeof(double), 0 }, - { typeof(decimal), 0 }, - { typeof(DateTime), 0 }, - { typeof(DateTimeOffset), 0 }, - { typeof(TimeSpan), 0 }, - { typeof(Guid), 0 }, - { typeof(Math), 0 }, - { typeof(Convert), 0 }, - { typeof(Uri), 0 }, + public static readonly IDictionary PredefinedTypes = new ConcurrentDictionary(new Dictionary { + { typeof(object), 0 }, + { typeof(bool), 0 }, + { typeof(char), 0 }, + { typeof(string), 0 }, + { typeof(sbyte), 0 }, + { typeof(byte), 0 }, + { typeof(short), 0 }, + { typeof(ushort), 0 }, + { typeof(int), 0 }, + { typeof(uint), 0 }, + { typeof(long), 0 }, + { typeof(ulong), 0 }, + { typeof(float), 0 }, + { typeof(double), 0 }, + { typeof(decimal), 0 }, + { typeof(DateTime), 0 }, + { typeof(DateTimeOffset), 0 }, + { typeof(TimeSpan), 0 }, + { typeof(Guid), 0 }, + { typeof(Math), 0 }, + { typeof(Convert), 0 }, + { typeof(Uri), 0 }, #if NET6_0_OR_GREATER - { typeof(DateOnly), 0 }, - { typeof(TimeOnly), 0 } + { typeof(DateOnly), 0 }, + { typeof(TimeOnly), 0 } #endif - }); + }); - static PredefinedTypesHelper() - { + static PredefinedTypesHelper() + { #if !(NET35 || SILVERLIGHT || NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) - //System.Data.Entity is always here, so overwrite short name of it with EntityFramework if EntityFramework is found. - //EF5(or 4.x??), System.Data.Objects.DataClasses.EdmFunctionAttribute - //There is also an System.Data.Entity, Version=3.5.0.0, but no Functions. - TryAdd("System.Data.Objects.EntityFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); - TryAdd("System.Data.Objects.SqlClient.SqlFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); - TryAdd("System.Data.Objects.SqlClient.SqlSpatialFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); + //System.Data.Entity is always here, so overwrite short name of it with EntityFramework if EntityFramework is found. + //EF5(or 4.x??), System.Data.Objects.DataClasses.EdmFunctionAttribute + //There is also an System.Data.Entity, Version=3.5.0.0, but no Functions. + TryAdd("System.Data.Objects.EntityFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); + TryAdd("System.Data.Objects.SqlClient.SqlFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); + TryAdd("System.Data.Objects.SqlClient.SqlSpatialFunctions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 1); - //EF6,System.Data.Entity.DbFunctionAttribute - TryAdd("System.Data.Entity.Core.Objects.EntityFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.DbFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.SqlServer.SqlFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); - TryAdd("System.Data.Entity.SqlServer.SqlSpatialFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + //EF6,System.Data.Entity.DbFunctionAttribute + TryAdd("System.Data.Entity.Core.Objects.EntityFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.DbFunctions, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.SqlServer.SqlFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); + TryAdd("System.Data.Entity.SqlServer.SqlSpatialFunctions, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 2); #endif #if NETSTANDARD2_0 - TryAdd($"Microsoft.EntityFrameworkCore.DynamicLinq.DynamicFunctions, Microsoft.EntityFrameworkCore.DynamicLinq, Version={Version}, Culture=neutral, PublicKeyToken=974e7e1b462f3693", 3); + TryAdd($"Microsoft.EntityFrameworkCore.DynamicLinq.DynamicFunctions, Microsoft.EntityFrameworkCore.DynamicLinq, Version={Version}, Culture=neutral, PublicKeyToken=974e7e1b462f3693", 3); #endif - } + } - private static void TryAdd(string typeName, int x) + private static void TryAdd(string typeName, int x) + { + try { - try + var efType = Type.GetType(typeName); + if (efType != null) { - Type? efType = Type.GetType(typeName); - if (efType != null) - { - PredefinedTypes.Add(efType, x); - } - } - catch - { - // in case of exception, do not add + PredefinedTypes.Add(efType, x); } } - - public static bool IsPredefinedType(ParsingConfig config, Type type) + catch { - Check.NotNull(config, nameof(config)); - Check.NotNull(type, nameof(type)); + // in case of exception, do not add + } + } - var nonNullableType = TypeHelper.GetNonNullableType(type); - if (PredefinedTypes.ContainsKey(nonNullableType)) - { - return true; - } + public static bool IsPredefinedType(ParsingConfig config, Type type) + { + Check.NotNull(config); + Check.NotNull(type); - return config.CustomTypeProvider != null && - (config.CustomTypeProvider.GetCustomTypes().Contains(type) || config.CustomTypeProvider.GetCustomTypes().Contains(nonNullableType)); + var nonNullableType = TypeHelper.GetNonNullableType(type); + if (PredefinedTypes.ContainsKey(nonNullableType)) + { + return true; } + + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + return config.CustomTypeProvider != null && + (config.CustomTypeProvider.GetCustomTypes().Contains(type) || config.CustomTypeProvider.GetCustomTypes().Contains(nonNullableType)); } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 3bd1332c..83d99980 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -8,1530 +8,1549 @@ using System.Reflection; using System.Runtime.CompilerServices; using FluentAssertions; +using Moq; using NFluent; using Xunit; -namespace System.Linq.Dynamic.Core.Tests +namespace System.Linq.Dynamic.Core.Tests; + +public class DynamicExpressionParserTests { - public class DynamicExpressionParserTests + public class Foo { - public class Foo - { - public Foo FooValue { get; set; } + public Foo FooValue { get; set; } + + public string Zero() => null; + + public string One(int x) => null; - public string Zero() => null; + public string Two(int x, int y) => null; + } + + private class MyClass + { + public List MyStrings { get; set; } - public string One(int x) => null; + public List MyClasses { get; set; } - public string Two(int x, int y) => null; + public int Foo() + { + return 42; } - private class MyClass + public void Bar() { - public List MyStrings { get; set; } + Name = nameof(Foo); + } - public List MyClasses { get; set; } + public string Name { get; set; } - public int Foo() - { - return 42; - } + public MyClass Child { get; set; } + } - public void Bar() - { - Name = nameof(Foo); - } + private class MyClassCustomTypeProvider : DefaultDynamicLinqCustomTypeProvider + { + public override HashSet GetCustomTypes() + { + var customTypes = base.GetCustomTypes(); + customTypes.Add(typeof(MyClass)); + return customTypes; + } + } - public string Name { get; set; } + private class ComplexParseLambda1Result + { + public int? Age; + public int TotalIncome; + public string Name; + } - public MyClass Child { get; set; } - } + [DynamicLinqType] + public class ComplexParseLambda3Result + { + public int? Age { get; set; } + public int TotalIncome { get; set; } + } + + public class CustomClassWithStaticMethod + { + public static int GetAge(int x) => x; + } - private class MyClassCustomTypeProvider : DefaultDynamicLinqCustomTypeProvider + public class CustomTextClass + { + public CustomTextClass(string origin) { - public override HashSet GetCustomTypes() - { - var customTypes = base.GetCustomTypes(); - customTypes.Add(typeof(MyClass)); - return customTypes; - } + Origin = origin; } - private class ComplexParseLambda1Result + public string Origin { get; } + + public static implicit operator string(CustomTextClass customTextValue) { - public int? Age; - public int TotalIncome; - public string Name; + return customTextValue?.Origin; } - [DynamicLinqType] - public class ComplexParseLambda3Result + public static implicit operator CustomTextClass(string origin) { - public int? Age { get; set; } - public int TotalIncome { get; set; } + return new CustomTextClass(origin); } - public class CustomClassWithStaticMethod + public override string ToString() { - public static int GetAge(int x) => x; + return Origin; } + } - public class CustomTextClass + public class CustomClassWithOneWayImplicitConversion + { + public CustomClassWithOneWayImplicitConversion(string origin) { - public CustomTextClass(string origin) - { - Origin = origin; - } - - public string Origin { get; } - - public static implicit operator string(CustomTextClass customTextValue) - { - return customTextValue?.Origin; - } + Origin = origin; + } - public static implicit operator CustomTextClass(string origin) - { - return new CustomTextClass(origin); - } + public string Origin { get; } - public override string ToString() - { - return Origin; - } + public static implicit operator CustomClassWithOneWayImplicitConversion(string origin) + { + return new CustomClassWithOneWayImplicitConversion(origin); } - public class CustomClassWithOneWayImplicitConversion + public override string ToString() { - public CustomClassWithOneWayImplicitConversion(string origin) - { - Origin = origin; - } - - public string Origin { get; } - - public static implicit operator CustomClassWithOneWayImplicitConversion(string origin) - { - return new CustomClassWithOneWayImplicitConversion(origin); - } - - public override string ToString() - { - return Origin; - } + return Origin; } + } - public class CustomClassWithReversedImplicitConversion + public class CustomClassWithReversedImplicitConversion + { + public CustomClassWithReversedImplicitConversion(string origin) { - public CustomClassWithReversedImplicitConversion(string origin) - { - Origin = origin; - } + Origin = origin; + } - public string Origin { get; } + public string Origin { get; } - public static implicit operator string(CustomClassWithReversedImplicitConversion origin) - { - return origin.ToString(); - } + public static implicit operator string(CustomClassWithReversedImplicitConversion origin) + { + return origin.ToString(); + } - public override string ToString() - { - return Origin; - } + public override string ToString() + { + return Origin; } + } - public class CustomClassWithValueTypeImplicitConversion + public class CustomClassWithValueTypeImplicitConversion + { + public CustomClassWithValueTypeImplicitConversion(int origin) { - public CustomClassWithValueTypeImplicitConversion(int origin) - { - Origin = origin; - } + Origin = origin; + } - public int Origin { get; } + public int Origin { get; } - public static implicit operator CustomClassWithValueTypeImplicitConversion(int origin) - { - return new CustomClassWithValueTypeImplicitConversion(origin); - } + public static implicit operator CustomClassWithValueTypeImplicitConversion(int origin) + { + return new CustomClassWithValueTypeImplicitConversion(origin); + } - public override string ToString() - { - return Origin.ToString(); - } + public override string ToString() + { + return Origin.ToString(); } + } - public class CustomClassWithReversedValueTypeImplicitConversion + public class CustomClassWithReversedValueTypeImplicitConversion + { + public CustomClassWithReversedValueTypeImplicitConversion(int origin) { - public CustomClassWithReversedValueTypeImplicitConversion(int origin) - { - Origin = origin; - } + Origin = origin; + } - public int Origin { get; } + public int Origin { get; } - public static implicit operator int(CustomClassWithReversedValueTypeImplicitConversion origin) - { - return origin.Origin; - } + public static implicit operator int(CustomClassWithReversedValueTypeImplicitConversion origin) + { + return origin.Origin; + } - public override string ToString() - { - return Origin.ToString(); - } + public override string ToString() + { + return Origin.ToString(); } + } - public class TestImplicitConversionContainer + public class TestImplicitConversionContainer + { + public TestImplicitConversionContainer( + CustomClassWithOneWayImplicitConversion oneWay, + CustomClassWithReversedImplicitConversion reversed, + CustomClassWithValueTypeImplicitConversion valueType, + CustomClassWithReversedValueTypeImplicitConversion reversedValueType) { - public TestImplicitConversionContainer( - CustomClassWithOneWayImplicitConversion oneWay, - CustomClassWithReversedImplicitConversion reversed, - CustomClassWithValueTypeImplicitConversion valueType, - CustomClassWithReversedValueTypeImplicitConversion reversedValueType) - { - OneWay = oneWay; - Reversed = reversed; - ValueType = valueType; - ReversedValueType = reversedValueType; - } + OneWay = oneWay; + Reversed = reversed; + ValueType = valueType; + ReversedValueType = reversedValueType; + } - public CustomClassWithOneWayImplicitConversion OneWay { get; } + public CustomClassWithOneWayImplicitConversion OneWay { get; } - public CustomClassWithReversedImplicitConversion Reversed { get; } + public CustomClassWithReversedImplicitConversion Reversed { get; } - public CustomClassWithValueTypeImplicitConversion ValueType { get; } + public CustomClassWithValueTypeImplicitConversion ValueType { get; } - public CustomClassWithReversedValueTypeImplicitConversion ReversedValueType { get; } - } + public CustomClassWithReversedValueTypeImplicitConversion ReversedValueType { get; } + } - public class TextHolder + public class TextHolder + { + public TextHolder(string name, CustomTextClass note) { - public TextHolder(string name, CustomTextClass note) - { - Name = name; - Note = note; - } + Name = name; + Note = note; + } - public string Name { get; } + public string Name { get; } - public CustomTextClass Note { get; } + public CustomTextClass Note { get; } - public override string ToString() - { - return Name + " (" + Note + ")"; - } + public override string ToString() + { + return Name + " (" + Note + ")"; } + } - public static class StaticHelper + public static class StaticHelper + { + public static Guid? GetGuid(string name) { - public static Guid? GetGuid(string name) - { - return Guid.NewGuid(); - } + return Guid.NewGuid(); } + } - public class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider - { - private HashSet _customTypes; + public class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider + { + private HashSet _customTypes; - public virtual HashSet GetCustomTypes() + public virtual HashSet GetCustomTypes() + { + if (_customTypes != null) { - if (_customTypes != null) - { - return _customTypes; - } - - _customTypes = new HashSet(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly })) - { - typeof(CustomClassWithStaticMethod), - typeof(StaticHelper) - }; return _customTypes; } - public Dictionary> GetExtensionMethods() + _customTypes = new HashSet(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly })) { - var types = GetCustomTypes(); + typeof(CustomClassWithStaticMethod), + typeof(StaticHelper) + }; + return _customTypes; + } - var list = new List>(); + public Dictionary> GetExtensionMethods() + { + var types = GetCustomTypes(); - foreach (var type in types) - { - var extensionMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) - .Where(x => x.IsDefined(typeof(ExtensionAttribute), false)).ToList(); + var list = new List>(); - extensionMethods.ForEach(x => list.Add(new Tuple(x.GetParameters()[0].ParameterType, x))); - } + foreach (var type in types) + { + var extensionMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + .Where(x => x.IsDefined(typeof(ExtensionAttribute), false)).ToList(); - return list.GroupBy(x => x.Item1, tuple => tuple.Item2).ToDictionary(key => key.Key, methods => methods.ToList()); + extensionMethods.ForEach(x => list.Add(new Tuple(x.GetParameters()[0].ParameterType, x))); } - public Type ResolveType(string typeName) - { - return Type.GetType(typeName); - } + return list.GroupBy(x => x.Item1, tuple => tuple.Item2).ToDictionary(key => key.Key, methods => methods.ToList()); + } - public Type ResolveTypeBySimpleName(string typeName) - { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - return ResolveTypeBySimpleName(assemblies, typeName); - } + public Type ResolveType(string typeName) + { + return Type.GetType(typeName); } - [Fact] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false_String() + public Type ResolveTypeBySimpleName(string typeName) { - // Assign - var config = new ParsingConfig - { - UseParameterizedNamesInDynamicQuery = false - }; + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + return ResolveTypeBySimpleName(assemblies, typeName); + } + } - // Act - var expression = DynamicExpressionParser.ParseLambda(config, true, "s => s == \"x\""); + [Fact] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false_String() + { + // Assign + var config = new ParsingConfig + { + UseParameterizedNamesInDynamicQuery = false + }; - // Assert - ConstantExpression constantExpression = (ConstantExpression)((BinaryExpression)expression.Body).Right; - object value = constantExpression.Value; + // Act + var expression = DynamicExpressionParser.ParseLambda(config, true, "s => s == \"x\""); - Check.That(value).IsEqualTo("x"); - } + // Assert + ConstantExpression constantExpression = (ConstantExpression)((BinaryExpression)expression.Body).Right; + object value = constantExpression.Value; - [Fact] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false_DateTime() + Check.That(value).IsEqualTo("x"); + } + + [Fact] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_false_DateTime() + { + // Assign + var config = new ParsingConfig { - // Assign - var config = new ParsingConfig - { - UseParameterizedNamesInDynamicQuery = false - }; + UseParameterizedNamesInDynamicQuery = false + }; - // Act - var expression = DynamicExpressionParser.ParseLambda(config, true, "D == \"2022-03-02\""); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, true, "D == \"2022-03-02\""); - // Assert - ConstantExpression constantExpression = (ConstantExpression)((BinaryExpression)expression.Body).Right; - object value = constantExpression.Value; + // Assert + ConstantExpression constantExpression = (ConstantExpression)((BinaryExpression)expression.Body).Right; + object value = constantExpression.Value; - Check.That(value).IsEqualTo(new DateTime(2022, 3, 2)); - } + Check.That(value).IsEqualTo(new DateTime(2022, 3, 2)); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true_Int() + [Fact] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true_Int() + { + // Assign + var config = new ParsingConfig { - // Assign - var config = new ParsingConfig - { - UseParameterizedNamesInDynamicQuery = true - }; + UseParameterizedNamesInDynamicQuery = true + }; - // Act - var expression = DynamicExpressionParser.ParseLambda(config, false, "Id = 42"); - var expressionAsString = expression.ToString(); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, false, "Id = 42"); + var expressionAsString = expression.ToString(); - // Assert - expressionAsString.Should().Be("Param_0 => (Param_0.Id == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.Int32]).Value)"); + // Assert + expressionAsString.Should().Be("Param_0 => (Param_0.Id == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.Int32]).Value)"); - ConstantExpression constantExpression = (ConstantExpression)((MemberExpression)((BinaryExpression)expression.Body).Right).Expression; - var wrappedObj = constantExpression!.Value; + ConstantExpression constantExpression = (ConstantExpression)((MemberExpression)((BinaryExpression)expression.Body).Right).Expression; + var wrappedObj = constantExpression!.Value; - PropertyInfo propertyInfo = wrappedObj!.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); - object value = propertyInfo!.GetValue(wrappedObj); + PropertyInfo propertyInfo = wrappedObj!.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); + object value = propertyInfo!.GetValue(wrappedObj); - Check.That(value).IsEqualTo(42); - } + Check.That(value).IsEqualTo(42); + } - [Fact(Skip = "Issue 645")] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true_DateTime() + [Fact(Skip = "Issue 645")] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_true_DateTime() + { + // Assign + var config = new ParsingConfig { - // Assign - var config = new ParsingConfig - { - UseParameterizedNamesInDynamicQuery = true - }; + UseParameterizedNamesInDynamicQuery = true + }; - // Act - var expression = DynamicExpressionParser.ParseLambda(config, false, "D = \"2022-11-16\""); - var expressionAsString = expression.ToString(); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, false, "D = \"2022-11-16\""); + var expressionAsString = expression.ToString(); - // Assert - expressionAsString.Should().Be("Param_0 => (Param_0.D == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.DateTime]).Value)"); + // Assert + expressionAsString.Should().Be("Param_0 => (Param_0.D == value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[System.DateTime]).Value)"); - ConstantExpression constantExpression = (ConstantExpression)((MemberExpression)((BinaryExpression)expression.Body).Right).Expression; - var wrappedObj = constantExpression!.Value; + ConstantExpression constantExpression = (ConstantExpression)((MemberExpression)((BinaryExpression)expression.Body).Right).Expression; + var wrappedObj = constantExpression!.Value; - PropertyInfo propertyInfo = wrappedObj!.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); - object value = propertyInfo!.GetValue(wrappedObj); + PropertyInfo propertyInfo = wrappedObj!.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); + object value = propertyInfo!.GetValue(wrappedObj); - Check.That(value).IsEqualTo(new DateTime(2022, 11, 16)); - } + Check.That(value).IsEqualTo(new DateTime(2022, 11, 16)); + } - [Theory] - [InlineData("NullableIntValue", "42")] - [InlineData("NullableDoubleValue", "42.23")] - public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_ForNullableProperty_true(string propName, string valueString) + [Theory] + [InlineData("NullableIntValue", "42")] + [InlineData("NullableDoubleValue", "42.23")] + public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_ForNullableProperty_true(string propName, string valueString) + { + // Assign + var culture = CultureInfo.CreateSpecificCulture("en-US"); + var config = new ParsingConfig { - // Assign - var culture = CultureInfo.CreateSpecificCulture("en-US"); - var config = new ParsingConfig - { - UseParameterizedNamesInDynamicQuery = true, - NumberParseCulture = culture - }; - - // Act - var expression = DynamicExpressionParser.ParseLambda(config, false, $"{propName} = {valueString}"); - var expressionAsString = expression.ToString(); + UseParameterizedNamesInDynamicQuery = true, + NumberParseCulture = culture + }; - // Assert - var queriedProp = typeof(SimpleValuesModel).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public)!; - var queriedPropType = queriedProp.PropertyType; - var queriedPropUnderlyingType = Nullable.GetUnderlyingType(queriedPropType); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, false, $"{propName} = {valueString}"); + var expressionAsString = expression.ToString(); - Check.That(expressionAsString).IsEqualTo($"Param_0 => (Param_0.{propName} == {ExpressionString.NullableConversion($"value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[{queriedPropUnderlyingType}]).Value")})"); - dynamic constantExpression = (ConstantExpression)((MemberExpression)((UnaryExpression)((BinaryExpression)expression.Body).Right).Operand).Expression; - object wrapperObj = constantExpression.Value; + // Assert + var queriedProp = typeof(SimpleValuesModel).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public)!; + var queriedPropType = queriedProp.PropertyType; + var queriedPropUnderlyingType = Nullable.GetUnderlyingType(queriedPropType); - var propertyInfo = wrapperObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public)!; - var value = propertyInfo.GetValue(wrapperObj); + Check.That(expressionAsString).IsEqualTo($"Param_0 => (Param_0.{propName} == {ExpressionString.NullableConversion($"value(System.Linq.Dynamic.Core.Parser.WrappedValue`1[{queriedPropUnderlyingType}]).Value")})"); + dynamic constantExpression = (ConstantExpression)((MemberExpression)((UnaryExpression)((BinaryExpression)expression.Body).Right).Operand).Expression; + object wrapperObj = constantExpression.Value; - value.Should().Be(Convert.ChangeType(valueString, Nullable.GetUnderlyingType(queriedPropType) ?? queriedPropType, culture)); - } + var propertyInfo = wrapperObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public)!; + var value = propertyInfo.GetValue(wrapperObj); - [Theory] - [InlineData("Where(x => x.SnowflakeId == {0})")] - [InlineData("Where(x => x.SnowflakeId = {0})")] - public void DynamicExpressionParser_ParseLambda_WithStructWithEquality(string query) - { - // Assign - var testList = User.GenerateSampleModels(51); - var qry = testList.AsQueryable(); + value.Should().Be(Convert.ChangeType(valueString, Nullable.GetUnderlyingType(queriedPropType) ?? queriedPropType, culture)); + } - // Act - var expectedX = (ulong)long.MaxValue + 3; + [Theory] + [InlineData("Where(x => x.SnowflakeId == {0})")] + [InlineData("Where(x => x.SnowflakeId = {0})")] + public void DynamicExpressionParser_ParseLambda_WithStructWithEquality(string query) + { + // Assign + var testList = User.GenerateSampleModels(51); + var qry = testList.AsQueryable(); - query = string.Format(query, expectedX); - var expression = DynamicExpressionParser.ParseLambda(qry.GetType(), null, query); - var del = expression.Compile(); - var result = del.DynamicInvoke(qry) as IEnumerable; + // Act + var expectedX = (ulong)long.MaxValue + 3; - var expected = qry.Where(gg => gg.SnowflakeId == new SnowflakeId(expectedX)).ToList(); + query = string.Format(query, expectedX); + var expression = DynamicExpressionParser.ParseLambda(qry.GetType(), null, query); + var del = expression.Compile(); + var result = del.DynamicInvoke(qry) as IEnumerable; - // Assert - Check.That(result).IsNotNull(); - Check.That(result).HasSize(expected.Count); - Check.That(result.ToArray()[0]).Equals(expected[0]); - } + var expected = qry.Where(gg => gg.SnowflakeId == new SnowflakeId(expectedX)).ToList(); - [Fact] - public void DynamicExpressionParser_ParseLambda_ToList() - { - // Arrange - var testList = User.GenerateSampleModels(51); - var qry = testList.AsQueryable(); - - // Act - var query = "OrderBy(gg => gg.Income).ToList()"; - var expression = DynamicExpressionParser.ParseLambda(qry.GetType(), null, query); - var del = expression.Compile(); - var result = del.DynamicInvoke(qry) as IEnumerable; - - var expected = qry.OrderBy(gg => gg.Income).ToList(); - - // Assert - Check.That(result).IsNotNull(); - Check.That(result).HasSize(expected.Count); - Check.That(result.ToArray()[0]).Equals(expected[0]); - } + // Assert + Check.That(result).IsNotNull(); + Check.That(result).HasSize(expected.Count); + Check.That(result.ToArray()[0]).Equals(expected[0]); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_Complex_1() - { - // Arrange - var testList = User.GenerateSampleModels(51); - var qry = testList.AsQueryable(); + [Fact] + public void DynamicExpressionParser_ParseLambda_ToList() + { + // Arrange + var testList = User.GenerateSampleModels(51); + var qry = testList.AsQueryable(); + + // Act + var query = "OrderBy(gg => gg.Income).ToList()"; + var expression = DynamicExpressionParser.ParseLambda(qry.GetType(), null, query); + var del = expression.Compile(); + var result = del.DynamicInvoke(qry) as IEnumerable; + + var expected = qry.OrderBy(gg => gg.Income).ToList(); + + // Assert + Check.That(result).IsNotNull(); + Check.That(result).HasSize(expected.Count); + Check.That(result.ToArray()[0]).Equals(expected[0]); + } - var externals = new Dictionary - { - {"Users", qry} - }; + [Fact] + public void DynamicExpressionParser_ParseLambda_Complex_1() + { + // Arrange + var testList = User.GenerateSampleModels(51); + var qry = testList.AsQueryable(); + + var externals = new Dictionary + { + {"Users", qry} + }; + + // Act + var query = + "Users.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age).Select(j => new (j.Key.Age, j.Sum(k => k.Income) As TotalIncome))"; + var expression = DynamicExpressionParser.ParseLambda(null, query, externals); + var del = expression.Compile(); + var result = del.DynamicInvoke() as IEnumerable; + + var expected = qry.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age) + .Select(j => new { j.Key.Age, TotalIncome = j.Sum(k => k.Income) }) + .Select(c => new ComplexParseLambda1Result { Age = c.Age, TotalIncome = c.TotalIncome }).Cast() + .ToArray(); + + // Assert + Check.That(result).IsNotNull(); + Check.That(result).HasSize(expected.Length); + Check.That(result.ToArray()[0]).Equals(expected[0]); + } - // Act - var query = - "Users.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age).Select(j => new (j.Key.Age, j.Sum(k => k.Income) As TotalIncome))"; - var expression = DynamicExpressionParser.ParseLambda(null, query, externals); - var del = expression.Compile(); - var result = del.DynamicInvoke() as IEnumerable; - - var expected = qry.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age) - .Select(j => new { j.Key.Age, TotalIncome = j.Sum(k => k.Income) }) - .Select(c => new ComplexParseLambda1Result { Age = c.Age, TotalIncome = c.TotalIncome }).Cast() - .ToArray(); - - // Assert - Check.That(result).IsNotNull(); - Check.That(result).HasSize(expected.Length); - Check.That(result.ToArray()[0]).Equals(expected[0]); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_Complex_2() + { + // Arrange + var testList = User.GenerateSampleModels(51); + var qry = testList.AsQueryable(); + + // Act + var query = + "GroupBy(x => new { x.Profile.Age }, it).OrderBy(gg => gg.Key.Age).Select(j => new (j.Key.Age, j.Sum(k => k.Income) As TotalIncome))"; + var expression = DynamicExpressionParser.ParseLambda(qry.GetType(), null, query); + var del = expression.Compile(); + var result = del.DynamicInvoke(qry) as IEnumerable; + + var expected = qry.GroupBy(x => new { x.Profile.Age }, x => x).OrderBy(gg => gg.Key.Age) + .Select(j => new { j.Key.Age, TotalIncome = j.Sum(k => k.Income) }) + .Select(c => new ComplexParseLambda1Result { Age = c.Age, TotalIncome = c.TotalIncome }).Cast() + .ToArray(); + + // Assert + Check.That(result).IsNotNull(); + Check.That(result).HasSize(expected.Length); + Check.That(result.ToArray()[0]).Equals(expected[0]); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_Complex_2() + [Fact] + public void DynamicExpressionParser_ParseLambda_Complex_3() + { + var config = new ParsingConfig { - // Arrange - var testList = User.GenerateSampleModels(51); - var qry = testList.AsQueryable(); - - // Act - var query = - "GroupBy(x => new { x.Profile.Age }, it).OrderBy(gg => gg.Key.Age).Select(j => new (j.Key.Age, j.Sum(k => k.Income) As TotalIncome))"; - var expression = DynamicExpressionParser.ParseLambda(qry.GetType(), null, query); - var del = expression.Compile(); - var result = del.DynamicInvoke(qry) as IEnumerable; - - var expected = qry.GroupBy(x => new { x.Profile.Age }, x => x).OrderBy(gg => gg.Key.Age) - .Select(j => new { j.Key.Age, TotalIncome = j.Sum(k => k.Income) }) - .Select(c => new ComplexParseLambda1Result { Age = c.Age, TotalIncome = c.TotalIncome }).Cast() - .ToArray(); - - // Assert - Check.That(result).IsNotNull(); - Check.That(result).HasSize(expected.Length); - Check.That(result.ToArray()[0]).Equals(expected[0]); - } + CustomTypeProvider = new TestCustomTypeProvider() + }; - [Fact] - public void DynamicExpressionParser_ParseLambda_Complex_3() + // Arrange + var testList = User.GenerateSampleModels(51); + var qry = testList.AsQueryable(); + + var externals = new Dictionary { - var config = new ParsingConfig - { - CustomTypeProvider = new TestCustomTypeProvider() - }; + {"Users", qry} + }; - // Arrange - var testList = User.GenerateSampleModels(51); - var qry = testList.AsQueryable(); + // Act + var stringExpression = + "Users.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age).Select(j => new System.Linq.Dynamic.Core.Tests.DynamicExpressionParserTests+ComplexParseLambda3Result{j.Key.Age, j.Sum(k => k.Income) As TotalIncome})"; + var expression = + DynamicExpressionParser.ParseLambda(config, null, stringExpression, externals); + var del = expression.Compile(); + var result = del.DynamicInvoke() as IEnumerable; - var externals = new Dictionary - { - {"Users", qry} - }; + var expected = qry.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age) + .Select(j => new ComplexParseLambda3Result { Age = j.Key.Age, TotalIncome = j.Sum(k => k.Income) }) + .Cast().ToArray(); - // Act - var stringExpression = - "Users.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age).Select(j => new System.Linq.Dynamic.Core.Tests.DynamicExpressionParserTests+ComplexParseLambda3Result{j.Key.Age, j.Sum(k => k.Income) As TotalIncome})"; - var expression = - DynamicExpressionParser.ParseLambda(config, null, stringExpression, externals); - var del = expression.Compile(); - var result = del.DynamicInvoke() as IEnumerable; - - var expected = qry.GroupBy(x => new { x.Profile.Age }).OrderBy(gg => gg.Key.Age) - .Select(j => new ComplexParseLambda3Result { Age = j.Key.Age, TotalIncome = j.Sum(k => k.Income) }) - .Cast().ToArray(); - - // Assert - Check.That(result).IsNotNull(); - Check.That(result).HasSize(expected.Length); - Check.That(result.ToArray()[0]).Equals(expected[0]); - } + // Assert + Check.That(result).IsNotNull(); + Check.That(result).HasSize(expected.Length); + Check.That(result.ToArray()[0]).Equals(expected[0]); + } + + [Fact] + public void DynamicExpressionParser_ParseLambda_Select_1() + { + // Arrange + var testList = User.GenerateSampleModels(51); + var qry = testList.AsQueryable(); - [Fact] - public void DynamicExpressionParser_ParseLambda_Select_1() + var externals = new Dictionary { - // Arrange - var testList = User.GenerateSampleModels(51); - var qry = testList.AsQueryable(); + {"Users", qry} + }; - var externals = new Dictionary - { - {"Users", qry} - }; + // Act + var query = "Users.Select(j => new User(j.Income As Income))"; + var expression = DynamicExpressionParser.ParseLambda(null, query, externals); + var del = expression.Compile(); + var result = del.DynamicInvoke(); - // Act - var query = "Users.Select(j => new User(j.Income As Income))"; - var expression = DynamicExpressionParser.ParseLambda(null, query, externals); - var del = expression.Compile(); - var result = del.DynamicInvoke(); + // Assert + Assert.NotNull(result); + } - // Assert - Assert.NotNull(result); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_Select_2() + { + // Arrange + var testList = User.GenerateSampleModels(5); + var qry = testList.AsQueryable(); - [Fact] - public void DynamicExpressionParser_ParseLambda_Select_2() + var externals = new Dictionary { - // Arrange - var testList = User.GenerateSampleModels(5); - var qry = testList.AsQueryable(); - - var externals = new Dictionary - { - {"Users", qry} - }; + {"Users", qry} + }; - // Act - var query = "Users.Select(j => j)"; - var expression = DynamicExpressionParser.ParseLambda(null, query, externals); - var del = expression.Compile(); - var result = del.DynamicInvoke(); + // Act + var query = "Users.Select(j => j)"; + var expression = DynamicExpressionParser.ParseLambda(null, query, externals); + var del = expression.Compile(); + var result = del.DynamicInvoke(); - // Assert - Assert.NotNull(result); - } + // Assert + Assert.NotNull(result); + } - // https://github.com/StefH/System.Linq.Dynamic.Core/issues/58 - [Fact] - public void DynamicExpressionParser_ParseLambda_Issue58() + // https://github.com/StefH/System.Linq.Dynamic.Core/issues/58 + [Fact] + public void DynamicExpressionParser_ParseLambda_Issue58() + { + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(MyClass) }); + var config = new ParsingConfig { - var expressionParams = new[] - { - Expression.Parameter(typeof(MyClass), "myObj") - }; + CustomTypeProvider = customTypeProvider.Object + }; + var expressionParams = new[] + { + Expression.Parameter(typeof(MyClass), "myObj") + }; - var myClassInstance = new MyClass(); - var invokersMerge = new List { myClassInstance }; + var myClassInstance = new MyClass(); + var invokersMerge = new List { myClassInstance }; - var expression = - DynamicExpressionParser.ParseLambda(false, expressionParams, null, "myObj.Foo()"); - var del = expression.Compile(); - var result = del.DynamicInvoke(invokersMerge.ToArray()); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, false, expressionParams, null, "myObj.Foo()"); + var del = expression.Compile(); + var result = del.DynamicInvoke(invokersMerge.ToArray()); - Check.That(result).Equals(42); - } + // Assert + Check.That(result).Equals(42); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_DuplicateParameterNames_ThrowsException() + [Fact] + public void DynamicExpressionParser_ParseLambda_DuplicateParameterNames_ThrowsException() + { + // Arrange + var parameters = new[] { - // Arrange - var parameters = new[] - { - Expression.Parameter(typeof(int), "x"), - Expression.Parameter(typeof(int), "x") - }; + Expression.Parameter(typeof(int), "x"), + Expression.Parameter(typeof(int), "x") + }; - // Act and Assert - Check.ThatCode(() => DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42")) - .Throws() - .WithMessage("The identifier 'x' was defined more than once"); - } + // Act and Assert + Check.ThatCode(() => DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42")) + .Throws() + .WithMessage("The identifier 'x' was defined more than once"); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_EmptyParameterList() - { - // Arrange - var pEmpty = new ParameterExpression[] { }; + [Fact] + public void DynamicExpressionParser_ParseLambda_EmptyParameterList() + { + // Arrange + var pEmpty = new ParameterExpression[] { }; - // Act - var @delegate = DynamicExpressionParser.ParseLambda(pEmpty, null, "1+2").Compile(); - var result = @delegate.DynamicInvoke() as int?; + // Act + var @delegate = DynamicExpressionParser.ParseLambda(pEmpty, null, "1+2").Compile(); + var result = @delegate.DynamicInvoke() as int?; - // Assert - Check.That(result).Equals(3); - } + // Assert + Check.That(result).Equals(3); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_ParameterName() + [Fact] + public void DynamicExpressionParser_ParseLambda_ParameterName() + { + // Arrange + var parameters = new[] { - // Arrange - var parameters = new[] - { - Expression.Parameter(typeof(int), "x") - }; + Expression.Parameter(typeof(int), "x") + }; - // Assert - var expressionX = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "x == 42"); - var expressionIT = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42"); + // Assert + var expressionX = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "x == 42"); + var expressionIT = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42"); - // Assert - Assert.Equal(typeof(bool), expressionX.Body.Type); - Assert.Equal(typeof(bool), expressionIT.Body.Type); - } + // Assert + Assert.Equal(typeof(bool), expressionX.Body.Type); + Assert.Equal(typeof(bool), expressionIT.Body.Type); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_ParameterName_Empty() + [Fact] + public void DynamicExpressionParser_ParseLambda_ParameterName_Empty() + { + // Arrange + var parameters = new[] { - // Arrange - var parameters = new[] - { - Expression.Parameter(typeof(int), "") - }; + Expression.Parameter(typeof(int), "") + }; - // Assert - var expression = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42"); + // Assert + var expression = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42"); - // Assert - Assert.Equal(typeof(bool), expression.Body.Type); - } + // Assert + Assert.Equal(typeof(bool), expression.Body.Type); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_ParameterName_Null() + [Fact] + public void DynamicExpressionParser_ParseLambda_ParameterName_Null() + { + // Arrange + var parameters = new[] { - // Arrange - var parameters = new[] - { - Expression.Parameter(typeof(int), null) - }; + Expression.Parameter(typeof(int), null) + }; - // Assert - var expression = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42"); + // Assert + var expression = DynamicExpressionParser.ParseLambda(parameters, typeof(bool), "it == 42"); - // Assert - Assert.Equal(typeof(bool), expression.Body.Type); - } + // Assert + Assert.Equal(typeof(bool), expression.Body.Type); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_ParameterExpressionMethodCall_ReturnsIntExpression() - { - var expression = DynamicExpressionParser.ParseLambda(true, - new[] { Expression.Parameter(typeof(int), "x") }, - typeof(int), - "x + 1"); - Assert.Equal(typeof(int), expression.Body.Type); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_ParameterExpressionMethodCall_ReturnsIntExpression() + { + var expression = DynamicExpressionParser.ParseLambda(true, + new[] { Expression.Parameter(typeof(int), "x") }, + typeof(int), + "x + 1"); + Assert.Equal(typeof(int), expression.Body.Type); + } - public static object[][] Decimals() + public static object[][] Decimals() + { + return new object[][] { - return new object[][] - { - new object[] { "de-DE", "1m", 1f }, - new object[] { "de-DE", "-42,0m", -42m }, - new object[] { "de-DE", "3,215m", 3.215m }, + new object[] { "de-DE", "1m", 1f }, + new object[] { "de-DE", "-42,0m", -42m }, + new object[] { "de-DE", "3,215m", 3.215m }, - new object[] { null, "1m", 1f }, - new object[] { null, "-42.0m", -42m }, - new object[] { null, "3.215m", 3.215m } - }; - } - [Theory] - [MemberData(nameof(Decimals))] - public void DynamicExpressionParser_ParseLambda_Decimal(string culture, string expression, decimal expected) + new object[] { null, "1m", 1f }, + new object[] { null, "-42.0m", -42m }, + new object[] { null, "3.215m", 3.215m } + }; + } + [Theory] + [MemberData(nameof(Decimals))] + public void DynamicExpressionParser_ParseLambda_Decimal(string culture, string expression, decimal expected) + { + // Arrange + var config = new ParsingConfig(); + if (culture != null) { - // Arrange - var config = new ParsingConfig(); - if (culture != null) - { - config.NumberParseCulture = CultureInfo.CreateSpecificCulture(culture); - } - - var parameters = new ParameterExpression[0]; - - // Act - var lambda = DynamicExpressionParser.ParseLambda(config, parameters, typeof(decimal), expression); - var result = lambda.Compile().DynamicInvoke(); - - // Assert - result.Should().Be(expected); + config.NumberParseCulture = CultureInfo.CreateSpecificCulture(culture); } - public static object[][] Floats() - { - return new object[][] - { - new object[] { "de-DE", "1F", 1f }, - new object[] { "de-DE", "1f", 1f }, - new object[] { "de-DE", "-42f", -42d }, - new object[] { "de-DE", "3,215f", 3.215d }, - - new object[] { null, "1F", 1f }, - new object[] { null, "1f", 1f }, - new object[] { null, "-42f", -42d }, - new object[] { null, "3.215f", 3.215d }, - }; - } - [Theory] - [MemberData(nameof(Floats))] - public void DynamicExpressionParser_ParseLambda_Float(string culture, string expression, float expected) - { - // Arrange - var config = new ParsingConfig(); - if (culture != null) - { - config.NumberParseCulture = CultureInfo.CreateSpecificCulture(culture); - } + var parameters = new ParameterExpression[0]; - var parameters = new ParameterExpression[0]; + // Act + var lambda = DynamicExpressionParser.ParseLambda(config, parameters, typeof(decimal), expression); + var result = lambda.Compile().DynamicInvoke(); - // Act - var lambda = DynamicExpressionParser.ParseLambda(config, parameters, typeof(float), expression); - var result = lambda.Compile().DynamicInvoke(); - - // Assert - result.Should().Be(expected); - } + // Assert + result.Should().Be(expected); + } - public static IEnumerable Doubles() + public static object[][] Floats() + { + return new object[][] + { + new object[] { "de-DE", "1F", 1f }, + new object[] { "de-DE", "1f", 1f }, + new object[] { "de-DE", "-42f", -42d }, + new object[] { "de-DE", "3,215f", 3.215d }, + + new object[] { null, "1F", 1f }, + new object[] { null, "1f", 1f }, + new object[] { null, "-42f", -42d }, + new object[] { null, "3.215f", 3.215d }, + }; + } + [Theory] + [MemberData(nameof(Floats))] + public void DynamicExpressionParser_ParseLambda_Float(string culture, string expression, float expected) + { + // Arrange + var config = new ParsingConfig(); + if (culture != null) { - return new object[][] - { - new object[] { "de-DE", "1D", 1d }, - new object[] { "de-DE", "1d", 1d }, - new object[] { "de-DE", "-42d", -42d }, - new object[] { "de-DE", "3,215d", 3.215d }, - new object[] { "de-DE", "1,2345E-4", 0.00012345d }, - new object[] { "de-DE", "1,2345E4", 12345d }, - - new object[] { null, "1D", 1d }, - new object[] { null, "1d", 1d }, - new object[] { null, "-42d", -42d }, - new object[] { null, "3.215d", 3.215d }, - new object[] { null, "1.2345E-4", 0.00012345d }, - new object[] { null, "1.2345E4", 12345d } - }; + config.NumberParseCulture = CultureInfo.CreateSpecificCulture(culture); } - [Theory] - [MemberData(nameof(Doubles))] - public void DynamicExpressionParser_ParseLambda_Double(string culture, string expression, double expected) - { - // Arrange - var config = new ParsingConfig(); - if (culture != null) - { - config.NumberParseCulture = CultureInfo.CreateSpecificCulture(culture); - } - var parameters = new ParameterExpression[0]; + var parameters = new ParameterExpression[0]; - // Act - var lambda = DynamicExpressionParser.ParseLambda(config, parameters, typeof(double), expression); - var result = lambda.Compile().DynamicInvoke(); + // Act + var lambda = DynamicExpressionParser.ParseLambda(config, parameters, typeof(float), expression); + var result = lambda.Compile().DynamicInvoke(); - // Assert - result.Should().Be(expected); - } - - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteral_ReturnsBooleanLambdaExpression() - { - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, typeof(bool), "Property1 == \"test\""); - Assert.Equal(typeof(bool), expression.Body.Type); - } + // Assert + result.Should().Be(expected); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteralEmpty_ReturnsBooleanLambdaExpression() + public static IEnumerable Doubles() + { + return new object[][] + { + new object[] { "de-DE", "1D", 1d }, + new object[] { "de-DE", "1d", 1d }, + new object[] { "de-DE", "-42d", -42d }, + new object[] { "de-DE", "3,215d", 3.215d }, + new object[] { "de-DE", "1,2345E-4", 0.00012345d }, + new object[] { "de-DE", "1,2345E4", 12345d }, + + new object[] { null, "1D", 1d }, + new object[] { null, "1d", 1d }, + new object[] { null, "-42d", -42d }, + new object[] { null, "3.215d", 3.215d }, + new object[] { null, "1.2345E-4", 0.00012345d }, + new object[] { null, "1.2345E4", 12345d } + }; + } + [Theory] + [MemberData(nameof(Doubles))] + public void DynamicExpressionParser_ParseLambda_Double(string culture, string expression, double expected) + { + // Arrange + var config = new ParsingConfig(); + if (culture != null) { - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, typeof(bool), "Property1 == \"\""); - Assert.Equal(typeof(bool), expression.Body.Type); + config.NumberParseCulture = CultureInfo.CreateSpecificCulture(culture); } - [Fact] - public void DynamicExpressionParser_ParseLambda_Config_StringLiteralEmpty_ReturnsBooleanLambdaExpression() - { - var config = new ParsingConfig(); - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, typeof(bool), "Property1 == \"\""); - Assert.Equal(typeof(bool), expression.Body.Type); - } + var parameters = new ParameterExpression[0]; - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteralEmbeddedQuote_ReturnsBooleanLambdaExpression() - { - // Act - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(bool), - string.Format("Property1 == {0}", "\"test \\\"string\"")); - - var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); - Assert.Equal(typeof(bool), expression.Body.Type); - Assert.Equal("\"test \"string\"", rightValue); - } + // Act + var lambda = DynamicExpressionParser.ParseLambda(config, parameters, typeof(double), expression); + var result = lambda.Compile().DynamicInvoke(); - /// - /// @see https://github.com/StefH/System.Linq.Dynamic.Core/issues/294 - /// - [Fact(Skip = "Fails on EntityFramework.DynamicLinq.Tests with 'An unexpected exception occurred while binding a dynamic operation'")] - public void DynamicExpressionParser_ParseLambda_MultipleLambdas() - { - var users = new[] - { - new { name = "Juan", age = 25 }, - new { name = "Juan", age = 25 }, - new { name = "David", age = 12 }, - new { name = "Juan", age = 25 }, - new { name = "Juan", age = 4 }, - new { name = "Pedro", age = 2 }, - new { name = "Juan", age = 25 } - }.ToList(); - - IQueryable query; - - // One lambda - var res1 = "[{\"Key\":{\"name\":\"Juan\"},\"nativeAggregates\":{\"ageSum\":104},\"Grouping\":[{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":4},{\"name\":\"Juan\",\"age\":25}]},{\"Key\":{\"name\":\"David\"},\"nativeAggregates\":{\"ageSum\":12},\"Grouping\":[{\"name\":\"David\",\"age\":12}]},{\"Key\":{\"name\":\"Pedro\"},\"nativeAggregates\":{\"ageSum\":2},\"Grouping\":[{\"name\":\"Pedro\",\"age\":2}]}]"; - query = users.AsQueryable(); - query = query.GroupBy("new(name as name)", "it"); - query = query.Select("new (it.Key as Key, new(it.Sum(x => x.age) as ageSum) as nativeAggregates, it as Grouping)"); - Assert.Equal(res1, Newtonsoft.Json.JsonConvert.SerializeObject(query)); - - // Multiple lambdas - var res2 = "[{\"Key\":{\"name\":\"Juan\"},\"nativeAggregates\":{\"ageSum\":0,\"ageSum2\":104},\"Grouping\":[{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":4},{\"name\":\"Juan\",\"age\":25}]},{\"Key\":{\"name\":\"David\"},\"nativeAggregates\":{\"ageSum\":0,\"ageSum2\":12},\"Grouping\":[{\"name\":\"David\",\"age\":12}]},{\"Key\":{\"name\":\"Pedro\"},\"nativeAggregates\":{\"ageSum\":0,\"ageSum2\":2},\"Grouping\":[{\"name\":\"Pedro\",\"age\":2}]}]"; - query = users.AsQueryable(); - query = query.GroupBy("new(name as name)", "it"); - query = query.Select("new (it.Key as Key, new(it.Sum(x => x.age > 25 ? 1 : 0) as ageSum, it.Sum(x => x.age) as ageSum2) as nativeAggregates, it as Grouping)"); - Assert.Equal(res2, Newtonsoft.Json.JsonConvert.SerializeObject(query)); - } + // Assert + result.Should().Be(expected); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteralStartEmbeddedQuote_ReturnsBooleanLambdaExpression() - { - // Act - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(bool), - string.Format("Property1 == {0}", "\"\\\"test\"")); - - var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); - Assert.Equal(typeof(bool), expression.Body.Type); - Assert.Equal("\"\"test\"", rightValue); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteral_ReturnsBooleanLambdaExpression() + { + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, typeof(bool), "Property1 == \"test\""); + Assert.Equal(typeof(bool), expression.Body.Type); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteral_MissingClosingQuote() - { - var expectedRightValue = "\"test\\\""; + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteralEmpty_ReturnsBooleanLambdaExpression() + { + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, typeof(bool), "Property1 == \"\""); + Assert.Equal(typeof(bool), expression.Body.Type); + } - Assert.Throws(() => DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(bool), - string.Format("Property1 == {0}", expectedRightValue))); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_Config_StringLiteralEmpty_ReturnsBooleanLambdaExpression() + { + var config = new ParsingConfig(); + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, typeof(bool), "Property1 == \"\""); + Assert.Equal(typeof(bool), expression.Body.Type); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteralEscapedBackslash_ReturnsBooleanLambdaExpression() - { - // Act - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(bool), - string.Format("Property1 == {0}", "\"test\\\\string\"")); - - var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); - Assert.Equal(typeof(Boolean), expression.Body.Type); - Assert.Equal("\"test\\string\"", rightValue); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteralEmbeddedQuote_ReturnsBooleanLambdaExpression() + { + // Act + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(bool), + string.Format("Property1 == {0}", "\"test \\\"string\"")); + + var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); + Assert.Equal(typeof(bool), expression.Body.Type); + Assert.Equal("\"test \"string\"", rightValue); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteralEscapedNewline_ReturnsBooleanLambdaExpression() - { - // Act - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(bool), - string.Format("Property1 == {0}", "\"test\\\\new\"")); - - var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); - Assert.Equal(typeof(Boolean), expression.Body.Type); - Assert.Equal("\"test\\new\"", rightValue); - } + /// + /// @see https://github.com/StefH/System.Linq.Dynamic.Core/issues/294 + /// + [Fact(Skip = "Fails on EntityFramework.DynamicLinq.Tests with 'An unexpected exception occurred while binding a dynamic operation'")] + public void DynamicExpressionParser_ParseLambda_MultipleLambdas() + { + var users = new[] + { + new { name = "Juan", age = 25 }, + new { name = "Juan", age = 25 }, + new { name = "David", age = 12 }, + new { name = "Juan", age = 25 }, + new { name = "Juan", age = 4 }, + new { name = "Pedro", age = 2 }, + new { name = "Juan", age = 25 } + }.ToList(); + + IQueryable query; + + // One lambda + var res1 = "[{\"Key\":{\"name\":\"Juan\"},\"nativeAggregates\":{\"ageSum\":104},\"Grouping\":[{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":4},{\"name\":\"Juan\",\"age\":25}]},{\"Key\":{\"name\":\"David\"},\"nativeAggregates\":{\"ageSum\":12},\"Grouping\":[{\"name\":\"David\",\"age\":12}]},{\"Key\":{\"name\":\"Pedro\"},\"nativeAggregates\":{\"ageSum\":2},\"Grouping\":[{\"name\":\"Pedro\",\"age\":2}]}]"; + query = users.AsQueryable(); + query = query.GroupBy("new(name as name)", "it"); + query = query.Select("new (it.Key as Key, new(it.Sum(x => x.age) as ageSum) as nativeAggregates, it as Grouping)"); + Assert.Equal(res1, Newtonsoft.Json.JsonConvert.SerializeObject(query)); + + // Multiple lambdas + var res2 = "[{\"Key\":{\"name\":\"Juan\"},\"nativeAggregates\":{\"ageSum\":0,\"ageSum2\":104},\"Grouping\":[{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":25},{\"name\":\"Juan\",\"age\":4},{\"name\":\"Juan\",\"age\":25}]},{\"Key\":{\"name\":\"David\"},\"nativeAggregates\":{\"ageSum\":0,\"ageSum2\":12},\"Grouping\":[{\"name\":\"David\",\"age\":12}]},{\"Key\":{\"name\":\"Pedro\"},\"nativeAggregates\":{\"ageSum\":0,\"ageSum2\":2},\"Grouping\":[{\"name\":\"Pedro\",\"age\":2}]}]"; + query = users.AsQueryable(); + query = query.GroupBy("new(name as name)", "it"); + query = query.Select("new (it.Key as Key, new(it.Sum(x => x.age > 25 ? 1 : 0) as ageSum, it.Sum(x => x.age) as ageSum2) as nativeAggregates, it as Grouping)"); + Assert.Equal(res2, Newtonsoft.Json.JsonConvert.SerializeObject(query)); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteral_Backslash() - { - // Assign - var expectedRightValue = "0"; - - //Act - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(Boolean), - string.Format("{0} >= {1}", "Property1.IndexOf(\"\\\\\")", expectedRightValue)); - - var leftValue = ((BinaryExpression)expression.Body).Left.ToString(); - var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); - - // Assert - Assert.Equal(typeof(Boolean), expression.Body.Type); - Assert.Equal("Property1.IndexOf(\"\\\")", leftValue); - Assert.Equal(expectedRightValue, rightValue); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteralStartEmbeddedQuote_ReturnsBooleanLambdaExpression() + { + // Act + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(bool), + string.Format("Property1 == {0}", "\"\\\"test\"")); + + var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); + Assert.Equal(typeof(bool), expression.Body.Type); + Assert.Equal("\"\"test\"", rightValue); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_StringLiteral_QuotationMark() - { - var expectedRightValue = "0"; - var expression = DynamicExpressionParser.ParseLambda( - new[] { Expression.Parameter(typeof(string), "Property1") }, - typeof(Boolean), - string.Format("{0} >= {1}", "Property1.IndexOf(\"\\\"\")", expectedRightValue)); - - var leftValue = ((BinaryExpression)expression.Body).Left.ToString(); - var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); - Assert.Equal(typeof(Boolean), expression.Body.Type); - Assert.Equal("Property1.IndexOf(\"\"\")", leftValue); - Assert.Equal(expectedRightValue, rightValue); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteral_MissingClosingQuote() + { + var expectedRightValue = "\"test\\\""; - [Fact] - public void DynamicExpressionParser_ParseLambda_TupleToStringMethodCall_ReturnsStringLambdaExpression() - { - var expression = DynamicExpressionParser.ParseLambda( - typeof(Tuple), - typeof(string), - "it.ToString()"); - Assert.Equal(typeof(string), expression.ReturnType); - } + Assert.Throws(() => DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(bool), + string.Format("Property1 == {0}", expectedRightValue))); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_IllegalMethodCall_ThrowsException() - { - Check.ThatCode(() => { DynamicExpressionParser.ParseLambda(typeof(IO.FileStream), null, "it.Close()"); }) - .Throws().WithMessage("Methods on type 'Stream' are not accessible"); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteralEscapedBackslash_ReturnsBooleanLambdaExpression() + { + // Act + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(bool), + string.Format("Property1 == {0}", "\"test\\\\string\"")); + + var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); + Assert.Equal(typeof(Boolean), expression.Body.Type); + Assert.Equal("\"test\\string\"", rightValue); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_CustomMethod() - { - // Assign - var config = new ParsingConfig - { - CustomTypeProvider = new TestCustomTypeProvider() - }; + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteralEscapedNewline_ReturnsBooleanLambdaExpression() + { + // Act + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(bool), + string.Format("Property1 == {0}", "\"test\\\\new\"")); + + var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); + Assert.Equal(typeof(Boolean), expression.Body.Type); + Assert.Equal("\"test\\new\"", rightValue); + } - var context = new CustomClassWithStaticMethod(); - var expression = $"{nameof(CustomClassWithStaticMethod)}.{nameof(CustomClassWithStaticMethod.GetAge)}(10)"; + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteral_Backslash() + { + // Assign + var expectedRightValue = "0"; + + //Act + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(Boolean), + string.Format("{0} >= {1}", "Property1.IndexOf(\"\\\\\")", expectedRightValue)); + + var leftValue = ((BinaryExpression)expression.Body).Left.ToString(); + var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); + + // Assert + Assert.Equal(typeof(Boolean), expression.Body.Type); + Assert.Equal("Property1.IndexOf(\"\\\")", leftValue); + Assert.Equal(expectedRightValue, rightValue); + } - // Act - var lambdaExpression = DynamicExpressionParser.ParseLambda(config, typeof(CustomClassWithStaticMethod), null, expression); - var del = lambdaExpression.Compile(); - var result = (int)del.DynamicInvoke(context); + [Fact] + public void DynamicExpressionParser_ParseLambda_StringLiteral_QuotationMark() + { + var expectedRightValue = "0"; + var expression = DynamicExpressionParser.ParseLambda( + new[] { Expression.Parameter(typeof(string), "Property1") }, + typeof(Boolean), + string.Format("{0} >= {1}", "Property1.IndexOf(\"\\\"\")", expectedRightValue)); + + var leftValue = ((BinaryExpression)expression.Body).Left.ToString(); + var rightValue = ((BinaryExpression)expression.Body).Right.ToString(); + Assert.Equal(typeof(Boolean), expression.Body.Type); + Assert.Equal("Property1.IndexOf(\"\"\")", leftValue); + Assert.Equal(expectedRightValue, rightValue); + } - // Assert - Check.That(result).IsEqualTo(10); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_TupleToStringMethodCall_ReturnsStringLambdaExpression() + { + var expression = DynamicExpressionParser.ParseLambda( + typeof(Tuple), + typeof(string), + "it.ToString()"); + Assert.Equal(typeof(string), expression.ReturnType); + } - // [Fact] - public void DynamicExpressionParser_ParseLambda_With_InnerStringLiteral() + [Fact] + public void DynamicExpressionParser_ParseLambda_CustomMethod() + { + // Assign + var config = new ParsingConfig { - // Assign - var originalTrueValue = "simple + \"quoted\""; - var doubleQuotedTrueValue = "simple + \"\"quoted\"\""; - var expressionText = $"iif(1>0, \"{doubleQuotedTrueValue}\", \"false\")"; - - // Act - var lambda = DynamicExpressionParser.ParseLambda(typeof(string), null, expressionText); - var del = lambda.Compile(); - var result = del.DynamicInvoke(string.Empty); - - // Assert - Check.That(result).IsEqualTo(originalTrueValue); - } + CustomTypeProvider = new TestCustomTypeProvider() + }; - [Fact] - public void DynamicExpressionParser_ParseLambda_With_Guid_Equals_Null() - { - // Arrange - var user = new User(); - var guidEmpty = Guid.Empty; - var someId = Guid.NewGuid(); - var expressionText = $"iif(@0.Id == null, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)"; - - // Act - var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); - var boolLambda = lambda as Expression>; - Assert.NotNull(boolLambda); - - var del = lambda.Compile(); - var result = (bool)del.DynamicInvoke(user); - - // Assert - Assert.True(result); - } + var context = new CustomClassWithStaticMethod(); + var expression = $"{nameof(CustomClassWithStaticMethod)}.{nameof(CustomClassWithStaticMethod.GetAge)}(10)"; - [Fact] - public void DynamicExpressionParser_ParseLambda_With_Null_Equals_Guid() - { - // Arrange - var user = new User(); - var someId = Guid.NewGuid(); - var expressionText = $"iif(null == @0.Id, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)"; + // Act + var lambdaExpression = DynamicExpressionParser.ParseLambda(config, typeof(CustomClassWithStaticMethod), null, expression); + var del = lambdaExpression.Compile(); + var result = (int)del.DynamicInvoke(context); - // Act - var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); - var boolLambda = lambda as Expression>; - Assert.NotNull(boolLambda); + // Assert + Check.That(result).IsEqualTo(10); + } - var del = lambda.Compile(); - var result = (bool)del.DynamicInvoke(user); + // [Fact] + public void DynamicExpressionParser_ParseLambda_With_InnerStringLiteral() + { + // Assign + var originalTrueValue = "simple + \"quoted\""; + var doubleQuotedTrueValue = "simple + \"\"quoted\"\""; + var expressionText = $"iif(1>0, \"{doubleQuotedTrueValue}\", \"false\")"; + + // Act + var lambda = DynamicExpressionParser.ParseLambda(typeof(string), null, expressionText); + var del = lambda.Compile(); + var result = del.DynamicInvoke(string.Empty); + + // Assert + Check.That(result).IsEqualTo(originalTrueValue); + } - // Assert - Assert.True(result); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_With_Guid_Equals_Null() + { + // Arrange + var user = new User(); + var guidEmpty = Guid.Empty; + var someId = Guid.NewGuid(); + var expressionText = $"iif(@0.Id == null, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)"; + + // Act + var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); + var boolLambda = lambda as Expression>; + Assert.NotNull(boolLambda); + + var del = lambda.Compile(); + var result = (bool)del.DynamicInvoke(user); + + // Assert + Assert.True(result); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_With_DateTime_Equals_String() - { - // Arrange - var someDateTime = "2022-03-02"; - var user = new Person - { - D = new DateTime(2022, 3, 2) - }; - var expressionText = $"D == \"{someDateTime}\""; + [Fact] + public void DynamicExpressionParser_ParseLambda_With_Null_Equals_Guid() + { + // Arrange + var user = new User(); + var someId = Guid.NewGuid(); + var expressionText = $"iif(null == @0.Id, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)"; - // Act - var lambda = DynamicExpressionParser.ParseLambda(typeof(Person), null, expressionText, user); - var dtLambda = lambda as Expression>; - Assert.NotNull(dtLambda); + // Act + var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); + var boolLambda = lambda as Expression>; + Assert.NotNull(boolLambda); - var del = lambda.Compile(); - var result = (bool)del.DynamicInvoke(user); + var del = lambda.Compile(); + var result = (bool)del.DynamicInvoke(user); - // Assert - Assert.True(result); - } + // Assert + Assert.True(result); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_With_Guid_Equals_String() + [Fact] + public void DynamicExpressionParser_ParseLambda_With_DateTime_Equals_String() + { + // Arrange + var someDateTime = "2022-03-02"; + var user = new Person { - // Arrange - var someId = Guid.NewGuid(); - var anotherId = Guid.NewGuid(); - var user = new User - { - Id = someId - }; - var guidEmpty = Guid.Empty; - var expressionText = $"iif(@0.Id == \"{someId}\", Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))"; + D = new DateTime(2022, 3, 2) + }; + var expressionText = $"D == \"{someDateTime}\""; - // Act - var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); - var guidLambda = lambda as Expression>; - Assert.NotNull(guidLambda); + // Act + var lambda = DynamicExpressionParser.ParseLambda(typeof(Person), null, expressionText, user); + var dtLambda = lambda as Expression>; + Assert.NotNull(dtLambda); - var del = lambda.Compile(); - var result = (Guid)del.DynamicInvoke(user); + var del = lambda.Compile(); + var result = (bool)del.DynamicInvoke(user); - // Assert - Assert.Equal(guidEmpty, result); - } + // Assert + Assert.True(result); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_With_Concat_String_CustomType() - { - // Arrange - var name = "name1"; - var note = "note1"; - var textHolder = new TextHolder(name, note); - var expressionText = "Name + \" (\" + Note + \")\""; + [Fact] + public void DynamicExpressionParser_ParseLambda_With_Guid_Equals_String() + { + // Arrange + var someId = Guid.NewGuid(); + var anotherId = Guid.NewGuid(); + var user = new User + { + Id = someId + }; + var guidEmpty = Guid.Empty; + var expressionText = $"iif(@0.Id == \"{someId}\", Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))"; + + // Act + var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); + var guidLambda = lambda as Expression>; + Assert.NotNull(guidLambda); + + var del = lambda.Compile(); + var result = (Guid)del.DynamicInvoke(user); + + // Assert + Assert.Equal(guidEmpty, result); + } - // Act 1 - var lambda = DynamicExpressionParser.ParseLambda(typeof(TextHolder), null, expressionText, textHolder); - var stringLambda = lambda as Expression>; + [Fact] + public void DynamicExpressionParser_ParseLambda_With_Concat_String_CustomType() + { + // Arrange + var name = "name1"; + var note = "note1"; + var textHolder = new TextHolder(name, note); + var expressionText = "Name + \" (\" + Note + \")\""; - // Assert 1 - Assert.NotNull(stringLambda); + // Act 1 + var lambda = DynamicExpressionParser.ParseLambda(typeof(TextHolder), null, expressionText, textHolder); + var stringLambda = lambda as Expression>; - // Act 2 - var del = lambda.Compile(); - var result = (string)del.DynamicInvoke(textHolder); + // Assert 1 + Assert.NotNull(stringLambda); - // Assert 2 - Assert.Equal("name1 (note1)", result); - } + // Act 2 + var del = lambda.Compile(); + var result = (string)del.DynamicInvoke(textHolder); - [Fact] - public void DynamicExpressionParser_ParseLambda_With_Concat_CustomType_String() - { - // Arrange - var name = "name1"; - var note = "note1"; - var textHolder = new TextHolder(name, note); - var expressionText = "Note + \" (\" + Name + \")\""; + // Assert 2 + Assert.Equal("name1 (note1)", result); + } - // Act 1 - var lambda = DynamicExpressionParser.ParseLambda(typeof(TextHolder), null, expressionText, textHolder); - var stringLambda = lambda as Expression>; + [Fact] + public void DynamicExpressionParser_ParseLambda_With_Concat_CustomType_String() + { + // Arrange + var name = "name1"; + var note = "note1"; + var textHolder = new TextHolder(name, note); + var expressionText = "Note + \" (\" + Name + \")\""; - // Assert 1 - Assert.NotNull(stringLambda); + // Act 1 + var lambda = DynamicExpressionParser.ParseLambda(typeof(TextHolder), null, expressionText, textHolder); + var stringLambda = lambda as Expression>; - // Act 2 - var del = lambda.Compile(); - var result = (string)del.DynamicInvoke(textHolder); + // Assert 1 + Assert.NotNull(stringLambda); - // Assert 2 - Assert.Equal("note1 (name1)", result); - } + // Act 2 + var del = lambda.Compile(); + var result = (string)del.DynamicInvoke(textHolder); - [Fact] - public void DynamicExpressionParser_ParseLambda_With_One_Way_Implicit_Conversions() - { - // Arrange - var testString = "test"; - var testInt = 6; - var container = new TestImplicitConversionContainer(testString, new CustomClassWithReversedImplicitConversion(testString), testInt, new CustomClassWithReversedValueTypeImplicitConversion(testInt)); + // Assert 2 + Assert.Equal("note1 (name1)", result); + } - var expressionTextString = $"OneWay == \"{testString}\""; - var expressionTextReversed = $"Reversed == \"{testString}\""; - var expressionTextValueType = $"ValueType == {testInt}"; - var expressionTextReversedValueType = $"ReversedValueType == {testInt}"; + [Fact] + public void DynamicExpressionParser_ParseLambda_With_One_Way_Implicit_Conversions() + { + // Arrange + var testString = "test"; + var testInt = 6; + var container = new TestImplicitConversionContainer(testString, new CustomClassWithReversedImplicitConversion(testString), testInt, new CustomClassWithReversedValueTypeImplicitConversion(testInt)); - var invertedExpressionTextString = $"\"{testString}\" == OneWay"; - var invertedExpressionTextReversed = $"\"{testString}\" == Reversed"; - var invertedExpressionTextValueType = $"{testInt} == ValueType"; - var invertedExpressionTextReversedValueType = $"{testInt} == ReversedValueType"; + var expressionTextString = $"OneWay == \"{testString}\""; + var expressionTextReversed = $"Reversed == \"{testString}\""; + var expressionTextValueType = $"ValueType == {testInt}"; + var expressionTextReversedValueType = $"ReversedValueType == {testInt}"; - // Act 1 - var lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextString); + var invertedExpressionTextString = $"\"{testString}\" == OneWay"; + var invertedExpressionTextReversed = $"\"{testString}\" == Reversed"; + var invertedExpressionTextValueType = $"{testInt} == ValueType"; + var invertedExpressionTextReversedValueType = $"{testInt} == ReversedValueType"; - // Assert 1 - Assert.NotNull(lambda); + // Act 1 + var lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextString); - // Act 2 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextReversed); + // Assert 1 + Assert.NotNull(lambda); - // Assert 2 - Assert.NotNull(lambda); + // Act 2 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextReversed); - // Act 3 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextValueType); + // Assert 2 + Assert.NotNull(lambda); - // Assert 3 - Assert.NotNull(lambda); + // Act 3 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextValueType); - // Act 4 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextReversedValueType); + // Assert 3 + Assert.NotNull(lambda); - // Assert 4 - Assert.NotNull(lambda); + // Act 4 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionTextReversedValueType); - // Act 5 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextString); + // Assert 4 + Assert.NotNull(lambda); - // Assert 5 - Assert.NotNull(lambda); + // Act 5 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextString); - // Act 6 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextReversed); + // Assert 5 + Assert.NotNull(lambda); - // Assert 6 - Assert.NotNull(lambda); + // Act 6 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextReversed); - // Act 7 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextValueType); + // Assert 6 + Assert.NotNull(lambda); - // Assert 7 - Assert.NotNull(lambda); + // Act 7 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextValueType); - // Act 8 - lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextReversedValueType); + // Assert 7 + Assert.NotNull(lambda); - // Assert 8 - Assert.NotNull(lambda); - } + // Act 8 + lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, invertedExpressionTextReversedValueType); + + // Assert 8 + Assert.NotNull(lambda); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_Operator_Less_Greater_With_Guids() + [Fact] + public void DynamicExpressionParser_ParseLambda_Operator_Less_Greater_With_Guids() + { + var config = new ParsingConfig { - var config = new ParsingConfig - { - CustomTypeProvider = new TestCustomTypeProvider() - }; + CustomTypeProvider = new TestCustomTypeProvider() + }; - // Arrange - var someId = Guid.NewGuid(); - var anotherId = Guid.NewGuid(); - var user = new User - { - Id = someId - }; - var guidEmpty = Guid.Empty; - var expressionText = $"iif(@0.Id == StaticHelper.GetGuid(\"name\"), Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))"; + // Arrange + var someId = Guid.NewGuid(); + var anotherId = Guid.NewGuid(); + var user = new User + { + Id = someId + }; + var guidEmpty = Guid.Empty; + var expressionText = $"iif(@0.Id == StaticHelper.GetGuid(\"name\"), Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))"; - // Act - var lambda = DynamicExpressionParser.ParseLambda(config, typeof(User), null, expressionText, user); - var guidLambda = lambda as Expression>; - Assert.NotNull(guidLambda); + // Act + var lambda = DynamicExpressionParser.ParseLambda(config, typeof(User), null, expressionText, user); + var guidLambda = lambda as Expression>; + Assert.NotNull(guidLambda); - var del = lambda.Compile(); - var result = (Guid)del.DynamicInvoke(user); + var del = lambda.Compile(); + var result = (Guid)del.DynamicInvoke(user); - // Assert - Assert.Equal(anotherId, result); - } + // Assert + Assert.Equal(anotherId, result); + } - [Theory] - [InlineData(true, "c => c.Age == 8", "c => (c.Age == 8)")] - [InlineData(true, "c => c.Name == \"test\"", "c => (c.Name == \"test\")")] - [InlineData(false, "c => c.Age == 8", "Param_0 => (Param_0.Age == 8)")] - [InlineData(false, "c => c.Name == \"test\"", "Param_0 => (Param_0.Name == \"test\")")] - public void DynamicExpressionParser_ParseLambda_RenameParameterExpression(bool renameParameterExpression, string expressionAsString, string expected) + [Theory] + [InlineData(true, "c => c.Age == 8", "c => (c.Age == 8)")] + [InlineData(true, "c => c.Name == \"test\"", "c => (c.Name == \"test\")")] + [InlineData(false, "c => c.Age == 8", "Param_0 => (Param_0.Age == 8)")] + [InlineData(false, "c => c.Name == \"test\"", "Param_0 => (Param_0.Name == \"test\")")] + public void DynamicExpressionParser_ParseLambda_RenameParameterExpression(bool renameParameterExpression, string expressionAsString, string expected) + { + // Arrange + var config = new ParsingConfig { - // Arrange - var config = new ParsingConfig - { - RenameParameterExpression = renameParameterExpression - }; + RenameParameterExpression = renameParameterExpression + }; - // Act - var expression = DynamicExpressionParser.ParseLambda(config, true, expressionAsString); - var result = expression.ToString(); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, true, expressionAsString); + var result = expression.ToString(); - // Assert - Check.That(result).IsEqualTo(expected); - } + // Assert + Check.That(result).IsEqualTo(expected); + } - [Theory] - [InlineData("c => c.Age == 8", "([a-z]{16}) =\\> \\(\\1\\.Age == 8\\)")] - [InlineData("c => c.Name == \"test\"", "([a-z]{16}) =\\> \\(\\1\\.Name == \"test\"\\)")] - public void DynamicExpressionParser_ParseLambda_RenameEmptyParameterExpressionNames(string expressionAsString, string expected) + [Theory] + [InlineData("c => c.Age == 8", "([a-z]{16}) =\\> \\(\\1\\.Age == 8\\)")] + [InlineData("c => c.Name == \"test\"", "([a-z]{16}) =\\> \\(\\1\\.Name == \"test\"\\)")] + public void DynamicExpressionParser_ParseLambda_RenameEmptyParameterExpressionNames(string expressionAsString, string expected) + { + // Arrange + var config = new ParsingConfig { - // Arrange - var config = new ParsingConfig - { - RenameEmptyParameterExpressionNames = true - }; + RenameEmptyParameterExpressionNames = true + }; - // Act - var expression = DynamicExpressionParser.ParseLambda(config, true, expressionAsString); - var result = expression.ToString(); + // Act + var expression = DynamicExpressionParser.ParseLambda(config, true, expressionAsString); + var result = expression.ToString(); - // Assert - Check.That(result).Matches(expected); - } + // Assert + Check.That(result).Matches(expected); + } - [Theory] - [InlineData(@"p0.Equals(""Testing"", 3)", "testinG", true)] - [InlineData(@"p0.Equals(""Testing"", StringComparison.InvariantCultureIgnoreCase)", "testinG", true)] - public void DynamicExpressionParser_ParseLambda_SupportEnumerationStringComparison(string expressionAsString, string testValue, bool expectedResult) - { - // Arrange - var p0 = Expression.Parameter(typeof(string), "p0"); + [Theory] + [InlineData(@"p0.Equals(""Testing"", 3)", "testinG", true)] + [InlineData(@"p0.Equals(""Testing"", StringComparison.InvariantCultureIgnoreCase)", "testinG", true)] + public void DynamicExpressionParser_ParseLambda_SupportEnumerationStringComparison(string expressionAsString, string testValue, bool expectedResult) + { + // Arrange + var p0 = Expression.Parameter(typeof(string), "p0"); - // Act - var expression = DynamicExpressionParser.ParseLambda(new[] { p0 }, typeof(bool), expressionAsString); - var del = expression.Compile(); - var result = del.DynamicInvoke(testValue) as bool?; + // Act + var expression = DynamicExpressionParser.ParseLambda(new[] { p0 }, typeof(bool), expressionAsString); + var del = expression.Compile(); + var result = del.DynamicInvoke(testValue) as bool?; - // Assert - Check.That(result).IsEqualTo(expectedResult); - } + // Assert + Check.That(result).IsEqualTo(expectedResult); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_Zero_Arguments() + [Fact] + public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_0_Arguments() + { + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(Foo) }); + var config = new ParsingConfig { - // Arrange - var expression = "np(FooValue.Zero().Length)"; + CustomTypeProvider = customTypeProvider.Object + }; + var expression = "np(FooValue.Zero().Length)"; - // Act - var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(Foo), null, expression, new Foo()); + // Act + var lambdaExpression = DynamicExpressionParser.ParseLambda(config, typeof(Foo), null, expression, new Foo()); - // Assert + // Assert #if NETCOREAPP3_1 - lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Zero() != null)), Convert(Param_0.FooValue.Zero().Length, Nullable`1), null)"); + lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Zero() != null)), Convert(Param_0.FooValue.Zero().Length, Nullable`1), null)"); #else - lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Zero() != null)), Convert(Param_0.FooValue.Zero().Length), null)"); + lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Zero() != null)), Convert(Param_0.FooValue.Zero().Length), null)"); #endif - } + } - [Fact] - public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_One_Argument() + [Fact] + public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_1_Argument() + { + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(Foo) }); + var config = new ParsingConfig { - // Arrange - var expression = "np(FooValue.One(1).Length)"; + CustomTypeProvider = customTypeProvider.Object + }; + var expression = "np(FooValue.One(1).Length)"; - // Act - var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(Foo), null, expression, new Foo()); + // Act + var lambdaExpression = DynamicExpressionParser.ParseLambda(config, typeof(Foo), null, expression, new Foo()); - // Assert + // Assert #if NETCOREAPP3_1 - lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.One(1) != null)), Convert(Param_0.FooValue.One(1).Length, Nullable`1), null)"); + lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.One(1) != null)), Convert(Param_0.FooValue.One(1).Length, Nullable`1), null)"); #else - lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.One(1) != null)), Convert(Param_0.FooValue.One(1).Length), null)"); + lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.One(1) != null)), Convert(Param_0.FooValue.One(1).Length), null)"); #endif - } + } - [Fact] - public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_Two_Arguments() + [Fact] + public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_2_Arguments() + { + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(Foo) }); + var config = new ParsingConfig { - // Arrange - var expression = "np(FooValue.Two(1, 42).Length)"; + CustomTypeProvider = customTypeProvider.Object + }; + var expression = "np(FooValue.Two(1, 42).Length)"; - // Act - var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(Foo), null, expression, new Foo()); + // Act + var lambdaExpression = DynamicExpressionParser.ParseLambda(config, typeof(Foo), null, expression, new Foo()); - // Assert + // Assert #if NETCOREAPP3_1 - lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Two(1, 42) != null)), Convert(Param_0.FooValue.Two(1, 42).Length, Nullable`1), null)"); + lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Two(1, 42) != null)), Convert(Param_0.FooValue.Two(1, 42).Length, Nullable`1), null)"); #else - lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Two(1, 42) != null)), Convert(Param_0.FooValue.Two(1, 42).Length), null)"); + lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Two(1, 42) != null)), Convert(Param_0.FooValue.Two(1, 42).Length), null)"); #endif - } + } - [Fact] - public void DynamicExpressionParser_ParseLambda_NullPropagation_MethodCallExpression() - { - // Arrange - var myClass = new MyClass(); - var dataSource = new { MyClasses = new[] { myClass, null } }; + [Fact] + public void DynamicExpressionParser_ParseLambda_NullPropagation_MethodCallExpression() + { + // Arrange + var myClass = new MyClass(); + var dataSource = new { MyClasses = new[] { myClass, null } }; - var expressionText = "np(MyClasses.FirstOrDefault())"; + var expressionText = "np(MyClasses.FirstOrDefault())"; - // Act - var expression = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, dataSource.GetType(), typeof(MyClass), expressionText); - var del = expression.Compile(); - var result = del.DynamicInvoke(dataSource) as MyClass; + // Act + var expression = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, dataSource.GetType(), typeof(MyClass), expressionText); + var del = expression.Compile(); + var result = del.DynamicInvoke(dataSource) as MyClass; - // Assert - result.Should().Be(myClass); - } + // Assert + result.Should().Be(myClass); + } - [Theory] - [InlineData("np(MyClasses.FirstOrDefault().Name)")] - [InlineData("np(MyClasses.FirstOrDefault(Name == \"a\").Name)")] - public void DynamicExpressionParser_ParseLambda_NullPropagation_MethodCallExpression_With_Property(string expressionText) - { - // Arrange - var dataSource = new MyClass(); + [Theory] + [InlineData("np(MyClasses.FirstOrDefault().Name)")] + [InlineData("np(MyClasses.FirstOrDefault(Name == \"a\").Name)")] + public void DynamicExpressionParser_ParseLambda_NullPropagation_MethodCallExpression_With_Property(string expressionText) + { + // Arrange + var dataSource = new MyClass(); - // Act - var expression = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, dataSource.GetType(), typeof(string), expressionText); - var del = expression.Compile(); - var result = del.DynamicInvoke(dataSource) as string; + // Act + var expression = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, dataSource.GetType(), typeof(string), expressionText); + var del = expression.Compile(); + var result = del.DynamicInvoke(dataSource) as string; - // Assert - result.Should().BeNull(); - } + // Assert + result.Should().BeNull(); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_ActionDelegate_VoidMethodCallExpression() - { - // Arrange - var dataSource = new MyClass(); - var expressionText = "it.Bar()"; - var parsingConfig = new ParsingConfig { CustomTypeProvider = new MyClassCustomTypeProvider() }; - dataSource.Name.Should().BeNull(); - - // Act - var expression = DynamicExpressionParser.ParseLambda(typeof(Action), parsingConfig, dataSource.GetType(), null, expressionText); - var del = expression.Compile(); - del.DynamicInvoke(dataSource); - - // Assert - dataSource.Name.Should().NotBeNullOrEmpty(); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_ActionDelegate_VoidMethodCallExpression() + { + // Arrange + var dataSource = new MyClass(); + var expressionText = "it.Bar()"; + var parsingConfig = new ParsingConfig { CustomTypeProvider = new MyClassCustomTypeProvider() }; + dataSource.Name.Should().BeNull(); + + // Act + var expression = DynamicExpressionParser.ParseLambda(typeof(Action), parsingConfig, dataSource.GetType(), null, expressionText); + var del = expression.Compile(); + del.DynamicInvoke(dataSource); + + // Assert + dataSource.Name.Should().NotBeNullOrEmpty(); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_String_TrimEnd_0_Parameters() - { - // Act - var expression = DynamicExpressionParser.ParseLambda(new ParsingConfig(), false, "TrimEnd().EndsWith(@0)", "test"); + [Fact] + public void DynamicExpressionParser_ParseLambda_String_TrimEnd_0_Parameters() + { + // Act + var expression = DynamicExpressionParser.ParseLambda(new ParsingConfig(), false, "TrimEnd().EndsWith(@0)", "test"); - var @delegate = expression.Compile(); + var @delegate = expression.Compile(); - var result = (bool)@delegate.DynamicInvoke("This is a test "); + var result = (bool)@delegate.DynamicInvoke("This is a test "); - // Assert - result.Should().BeTrue(); - } + // Assert + result.Should().BeTrue(); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_String_TrimEnd_1_Parameter() - { - // Act - var expression = DynamicExpressionParser.ParseLambda(new ParsingConfig(), false, "TrimEnd('.').EndsWith(@0)", "test"); + [Fact] + public void DynamicExpressionParser_ParseLambda_String_TrimEnd_1_Parameter() + { + // Act + var expression = DynamicExpressionParser.ParseLambda(new ParsingConfig(), false, "TrimEnd('.').EndsWith(@0)", "test"); - var @delegate = expression.Compile(); + var @delegate = expression.Compile(); - var result = (bool)@delegate.DynamicInvoke("This is a test..."); + var result = (bool)@delegate.DynamicInvoke("This is a test..."); - // Assert - result.Should().BeTrue(); - } + // Assert + result.Should().BeTrue(); + } - public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider - { - public override HashSet GetCustomTypes() => new HashSet(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; - } + public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider + { + public override HashSet GetCustomTypes() => new HashSet(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; + } - [Fact] - public void DynamicExpressionParser_ParseLambda_GenericExtensionMethod() + [Fact] + public void DynamicExpressionParser_ParseLambda_GenericExtensionMethod() + { + // Arrange + var testList = User.GenerateSampleModels(51); + var config = new ParsingConfig { - // Arrange - var testList = User.GenerateSampleModels(51); - var config = new ParsingConfig - { - CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod(), - PrioritizePropertyOrFieldOverTheType = true - }; + CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod(), + PrioritizePropertyOrFieldOverTheType = true + }; - // Act - var query = "x => MethodsItemExtension.Functions.EfCoreCollate(x.UserName, \"tlh-KX\")==\"User4\" || MethodsItemExtension.Functions.EfCoreCollate(x.UserName, \"tlh-KX\")==\"User2\""; - var expression = DynamicExpressionParser.ParseLambda(config, false, query); - var del = expression.Compile(); + // Act + var query = "x => MethodsItemExtension.Functions.EfCoreCollate(x.UserName, \"tlh-KX\")==\"User4\" || MethodsItemExtension.Functions.EfCoreCollate(x.UserName, \"tlh-KX\")==\"User2\""; + var expression = DynamicExpressionParser.ParseLambda(config, false, query); + var del = expression.Compile(); - var result = Enumerable.Where(testList, del); + var result = Enumerable.Where(testList, del); - var expected = testList.Where(x => new string[] { "User4", "User2" }.Contains(x.UserName)).ToList(); + var expected = testList.Where(x => new string[] { "User4", "User2" }.Contains(x.UserName)).ToList(); - // Assert - Check.That(result).IsNotNull(); - Check.That(result).HasSize(expected.Count); - Check.That(result).Equals(expected); - } + // Assert + Check.That(result).IsNotNull(); + Check.That(result).HasSize(expected.Count); + Check.That(result).Equals(expected); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_Action() - { - // Arrange - var action = (Action)DynamicExpressionParser.ParseLambda(typeof(Action), new[] { Expression.Parameter(typeof(int), "x") }, typeof(int), "x + 1").Compile(); + [Fact] + public void DynamicExpressionParser_ParseLambda_Action() + { + // Arrange + var action = (Action)DynamicExpressionParser.ParseLambda(typeof(Action), new[] { Expression.Parameter(typeof(int), "x") }, typeof(int), "x + 1").Compile(); - // Act - action(3); - } + // Act + action(3); + } - [Fact] - public void DynamicExpressionParser_ParseLambda_Func() - { - // Arrange - var func = (Func)DynamicExpressionParser.ParseLambda( - typeof(Func), - new[] - { - Expression.Parameter(typeof(int), "x") - }, - typeof(int), - "x + 1" - ).Compile(); - - // Act - var result = func(4); - - // Assert - result.Should().Be(5); - } + [Fact] + public void DynamicExpressionParser_ParseLambda_Func() + { + // Arrange + var func = (Func)DynamicExpressionParser.ParseLambda( + typeof(Func), + new[] + { + Expression.Parameter(typeof(int), "x") + }, + typeof(int), + "x + 1" + ).Compile(); - [Theory] - [InlineData("value", "value != null && value == 1", 1, true)] - [InlineData("value", "value != null && value == 1", 5, false)] - [InlineData("x", "value != null && value == 1", 1, true)] - [InlineData("x", "value != null && value == 1", 5, false)] - [InlineData(null, "value != null && value == 1", 1, true)] - [InlineData(null, "value != null && value == 1", 5, false)] - [InlineData("value", "value => value != null && value == 1", 1, true)] - [InlineData("value", "value => value != null && value == 1", 5, false)] - public void DynamicExpressionParser_ParseLambda_Func2(string? paramName, string test, int? input, bool expected) - { - // Arrange - var nullableType = typeof(int?); - var delegateType = typeof(Func<,>).MakeGenericType(nullableType, typeof(bool)); - var valueParameter = paramName is not null ? Expression.Parameter(nullableType, paramName) : Expression.Parameter(nullableType); - - // Act 1 - var expression = DynamicExpressionParser.ParseLambda( - delegateType, - new ParsingConfig(), - new[] { valueParameter }, - typeof(bool), - test - ); - - // Act 2 - var compiledExpression = expression.Compile(); - var result = compiledExpression.DynamicInvoke(input); - - // Assert - result.Should().Be(expected); - } + // Act + var result = func(4); + + // Assert + result.Should().Be(5); + } + + [Theory] + [InlineData("value", "value != null && value == 1", 1, true)] + [InlineData("value", "value != null && value == 1", 5, false)] + [InlineData("x", "value != null && value == 1", 1, true)] + [InlineData("x", "value != null && value == 1", 5, false)] + [InlineData(null, "value != null && value == 1", 1, true)] + [InlineData(null, "value != null && value == 1", 5, false)] + [InlineData("value", "value => value != null && value == 1", 1, true)] + [InlineData("value", "value => value != null && value == 1", 5, false)] + public void DynamicExpressionParser_ParseLambda_Func2(string? paramName, string test, int? input, bool expected) + { + // Arrange + var nullableType = typeof(int?); + var delegateType = typeof(Func<,>).MakeGenericType(nullableType, typeof(bool)); + var valueParameter = paramName is not null ? Expression.Parameter(nullableType, paramName) : Expression.Parameter(nullableType); + + // Act 1 + var expression = DynamicExpressionParser.ParseLambda( + delegateType, + new ParsingConfig(), + new[] { valueParameter }, + typeof(bool), + test + ); + + // Act 2 + var compiledExpression = expression.Compile(); + var result = compiledExpression.DynamicInvoke(input); + + // Assert + result.Should().Be(expected); } } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs new file mode 100644 index 00000000..b858dc5c --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.MethodCall.cs @@ -0,0 +1,253 @@ +using System.Collections.Generic; +using System.Linq.Dynamic.Core.CustomTypeProviders; +using System.Linq.Dynamic.Core.Tests.Helpers.Models; +using FluentAssertions; +using Moq; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests; + +public partial class ExpressionTests +{ + private static ParsingConfig CreateParsingConfigForMethodCallTests() + { + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(User), typeof(Methods), typeof(Foo) }); + return new ParsingConfig + { + CustomTypeProvider = customTypeProvider.Object + }; + } + + private class DefaultDynamicLinqCustomTypeProviderForStaticTesting : DefaultDynamicLinqCustomTypeProvider + { + public override HashSet GetCustomTypes() => new(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; + } + + private static ParsingConfig CreateParsingConfigForStaticMethodCallTests() + { + return new ParsingConfig + { + CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForStaticTesting(), + PrioritizePropertyOrFieldOverTheType = true + }; + } + + [Fact] + public void ExpressionTests_MethodCall_NoParams() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var users = User.GenerateSampleModels(3); + + // Act + var expected = users.Where(u => u.TestMethod1()); + var result = users.AsQueryable().Where(config, "TestMethod1()"); + + // Assert + Assert.Equal(expected.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_OneParam_With_it() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var users = User.GenerateSampleModels(3); + + // Act + var expected = users.Where(u => u.TestMethod2(u)); + var result = users.AsQueryable().Where(config, "TestMethod2(it)"); + + // Assert + Assert.Equal(expected.Count(), result.Count()); + } + + + [Fact] + public void ExpressionTests_MethodCall_OneParam_With_User() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var users = User.GenerateSampleModels(10); + var testUser = users[2]; + + // Act + var expected = users.Where(u => u.TestMethod3(testUser)); + var result = users.AsQueryable().Where(config, "TestMethod3(@0)", testUser); + + // Assert + Assert.Equal(expected.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_GenericStatic() + { + // Arrange + var config = CreateParsingConfigForStaticMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); + + // Act + var expectedResult = list.Where(x => Methods.StaticGenericMethod(x)); + var result = list.AsQueryable().Where(config, "Methods.StaticGenericMethod(it)"); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_Generic() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); + + // Act + var methods = new Methods(); + var expectedResult = list.Where(x => methods.GenericMethod(x)); + var result = list.AsQueryable().Where(config, "@0.GenericMethod(it)", methods); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_GenericExtension() + { + // Arrange + var config = CreateParsingConfigForStaticMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); + + // Act + var expectedResult = list.Where(x => MethodsItemExtension.Functions.EfCoreCollate(x.Value, "tlh-KX") == 2); + var result = list.AsQueryable().Where(config, "MethodsItemExtension.Functions.EfCoreCollate(it.Value,\"tlh-KX\")==2"); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_ValueTypeToValueTypeParameter() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }; + + // Act + var methods = new Methods(); + var expectedResult = list.Where(x => methods.Method1(x)); + var result = list.AsQueryable().Where(config, "@0.Method1(it)", methods); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_ValueTypeToObjectParameterWithCast() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }; + + // Act + var methods = new Methods(); + var expectedResult = list.Where(x => methods.Method2(x)); + var result = list.AsQueryable().Where(config, "@0.Method2(object(it))", methods); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_ValueTypeToObjectParameterWithoutCast() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }; + + // Act + var methods = new Methods(); + var expectedResult = list.Where(x => methods.Method2(x)); + var result = list.AsQueryable().Where(config, "@0.Method2(it)", methods); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_NullableValueTypeToObjectParameter() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var list = new int?[] { 0, 1, 2, 3, 4, null }; + + // Act + var methods = new Methods(); + var expectedResult = list.Where(x => methods.Method2(x)); + var result = list.AsQueryable().Where(config, "@0.Method2(it)", methods); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_MethodCall_ReferenceTypeToObjectParameter() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); + + // Act + var methods = new Methods(); + var expectedResult = list.Where(x => methods.Method3(x)); + var result = list.AsQueryable().Where(config, "@0.Method3(it)", methods); + + // Assert + Assert.Equal(expectedResult.Count(), result.Count()); + } + + [Fact] + public void ExpressionTests_NullPropagating_InstanceMethod_0_Arguments() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var expression = "np(FooValue.Zero().Length)"; + var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable(); + + // Act + var result = q.Select(config, expression).FirstOrDefault() as int?; + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void ExpressionTests_NullPropagating_InstanceMethod_1_Argument() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var expression = "np(FooValue.One(1).Length)"; + var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable(); + + // Act + var result = q.Select(config, expression).FirstOrDefault() as int?; + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void ExpressionTests_NullPropagating_InstanceMethod_2_Arguments() + { + // Arrange + var config = CreateParsingConfigForMethodCallTests(); + var expression = "np(FooValue.Two(1, 42).Length)"; + var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable(); + + // Act + var result = q.Select(config, expression).FirstOrDefault() as int?; + + // Assert + result.Should().BeNull(); + } +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index f951d6e3..5d7e7a9c 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -23,7 +23,7 @@ public enum TestEnumPublic : sbyte Var6 = 16 } - public class ExpressionTests + public partial class ExpressionTests { public enum TestEnum2 : sbyte { @@ -1480,174 +1480,6 @@ public void ExpressionTests_LogicalAndOr() Assert.Equal(qry.Where(x => (x & 32) > 0).ToArray(), result2.ToArray()); } - [Fact] - public void ExpressionTests_Method_NoParams() - { - // Arrange - var users = User.GenerateSampleModels(3); - - // Act - var expected = users.Where(u => u.TestMethod1()); - var result = users.AsQueryable().Where("TestMethod1()"); - - // Assert - Assert.Equal(expected.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_Method_OneParam_With_it() - { - // Arrange - var users = User.GenerateSampleModels(3); - - // Act - var expected = users.Where(u => u.TestMethod2(u)); - var result = users.AsQueryable().Where("TestMethod2(it)"); - - // Assert - Assert.Equal(expected.Count(), result.Count()); - } - - public class DefaultDynamicLinqCustomTypeProviderForStaticTesting : CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider - { - public override HashSet GetCustomTypes() => new HashSet(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; - } - - [Fact] - public void ExpressionTests_MethodCall_GenericStatic() - { - var config = new ParsingConfig - { - CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForStaticTesting() - }; - - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); - - // Act - var expectedResult = list.Where(x => Methods.StaticGenericMethod(x)); - var result = list.AsQueryable().Where(config, "Methods.StaticGenericMethod(it)"); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_Generic() - { - var config = new ParsingConfig - { - CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForStaticTesting() - }; - - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => methods.GenericMethod(x)); - var result = list.AsQueryable().Where("@0.GenericMethod(it)", methods); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_GenericExtension() - { - var config = new ParsingConfig - { - CustomTypeProvider = new DefaultDynamicLinqCustomTypeProviderForStaticTesting(), - PrioritizePropertyOrFieldOverTheType = true - }; - - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => MethodsItemExtension.Functions.EfCoreCollate(x.Value, "tlh-KX") == 2); - var result = list.AsQueryable().Where(config, "MethodsItemExtension.Functions.EfCoreCollate(it.Value,\"tlh-KX\")==2"); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_ValueTypeToValueTypeParameter() - { - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }; - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => methods.Method1(x)); - var result = list.AsQueryable().Where("@0.Method1(it)", methods); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_ValueTypeToObjectParameterWithCast() - { - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }; - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => methods.Method2(x)); - var result = list.AsQueryable().Where("@0.Method2(object(it))", methods); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_ValueTypeToObjectParameterWithoutCast() - { - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }; - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => methods.Method2(x)); - var result = list.AsQueryable().Where("@0.Method2(it)", methods); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_NullableValueTypeToObjectParameter() - { - // Arrange - var list = new int?[] { 0, 1, 2, 3, 4, null }; - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => methods.Method2(x)); - var result = list.AsQueryable().Where("@0.Method2(it)", methods); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - - [Fact] - public void ExpressionTests_MethodCall_ReferenceTypeToObjectParameter() - { - // Arrange - var list = new[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray(); - - // Act - var methods = new Methods(); - var expectedResult = list.Where(x => methods.Method3(x)); - var result = list.AsQueryable().Where("@0.Method3(it)", methods); - - // Assert - Assert.Equal(expectedResult.Count(), result.Count()); - } - [Fact] public void ExpressionTests_NewAnonymousType_Paren() { @@ -1676,21 +1508,6 @@ public void ExpressionTests_NewAnonymousType_CurlyParen() Check.That(result).Equals(expectedResult); } - [Fact] - public void ExpressionTests_Method_OneParam_With_user() - { - // Arrange - var users = User.GenerateSampleModels(10); - var testUser = users[2]; - - // Act - var expected = users.Where(u => u.TestMethod3(testUser)); - var result = users.AsQueryable().Where("TestMethod3(@0)", testUser); - - // Assert - Assert.Equal(expected.Count(), result.Count()); - } - [Fact] public void ExpressionTests_Modulo_Number() { @@ -1899,50 +1716,7 @@ public void ExpressionTests_NullPropagating_Config_Has_UseDefault(string test, s queryAsString = queryAsString.Substring(queryAsString.IndexOf(".Select") + 1).TrimEnd(']'); Check.That(queryAsString).Equals(query); } - - - [Fact] - public void ExpressionTests_NullPropagating_InstanceMethod_Zero_Arguments() - { - // Arrange 1 - var expression = "np(FooValue.Zero().Length)"; - var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable(); - - // Act 2 - var result = q.Select(expression).FirstOrDefault() as int?; - - // Assert 2 - result.Should().BeNull(); - } - - [Fact] - public void ExpressionTests_NullPropagating_InstanceMethod_One_Argument() - { - // Arrange - var expression = "np(FooValue.One(1).Length)"; - var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable(); - - // Act - var result = q.Select(expression).FirstOrDefault() as int?; - - // Assert - result.Should().BeNull(); - } - - [Fact] - public void ExpressionTests_NullPropagating_InstanceMethod_Two_Arguments() - { - // Arrange - var expression = "np(FooValue.Two(1, 42).Length)"; - var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable(); - - // Act - var result = q.Select(expression).FirstOrDefault() as int?; - - // Assert - result.Should().BeNull(); - } - + [Fact] public void ExpressionTests_NullPropagation_Method() { diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Methods.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Methods.cs index 21ad0d94..04b14dd4 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Methods.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Methods.cs @@ -1,64 +1,84 @@ -using Xunit; +using System.Collections.Generic; +using System.Linq.Dynamic.Core.CustomTypeProviders; +using Moq; +using Xunit; -namespace System.Linq.Dynamic.Core.Tests +namespace System.Linq.Dynamic.Core.Tests; + +public partial class QueryableTests { - public partial class QueryableTests + [Fact] + public void CallMethod() { - [Fact] - public void CallMethod() + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(Test) }); + var config = new ParsingConfig { - // Arrange - var query = new[] { new Test() }.AsQueryable(); + CustomTypeProvider = customTypeProvider.Object + }; + var query = new[] { new Test() }.AsQueryable(); - // Act - var result = query.Select("t => t.GetDecimal()").First(); + // Act + var result = query.Select(config, "t => t.GetDecimal()").First(); - // Assert - Assert.Equal(42, result); - } + // Assert + Assert.Equal(42, result); + } - [Fact] - public void CallMethodWhichReturnsNullable() + [Fact] + public void CallMethodWhichReturnsNullable() + { + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(Test) }); + var config = new ParsingConfig { - // Arrange - var query = new[] { new Test() }.AsQueryable(); + CustomTypeProvider = customTypeProvider.Object + }; + var query = new[] { new Test() }.AsQueryable(); - // Act - var result = query.Select("t => t.GetNullableDecimal()").First(); + // Act + var result = query.Select(config, "t => t.GetNullableDecimal()").First(); - // Assert - Assert.Equal(null, result); - } + // Assert + Assert.Equal(null, result); + } - [Fact] - public void CallMethodWhichReturnsNullable_WithValue() + [Fact] + public void CallMethodWhichReturnsNullable_WithValue() + { + // Arrange + var customTypeProvider = new Mock(); + customTypeProvider.Setup(c => c.GetCustomTypes()).Returns(new HashSet { typeof(Test) }); + var config = new ParsingConfig { - // Arrange - var query = new[] { new Test() }.AsQueryable(); + CustomTypeProvider = customTypeProvider.Object + }; + var query = new[] { new Test() }.AsQueryable(); - // Act - var result = query.Select("t => t.GetNullableDecimalWithValue()").First(); + // Act + var result = query.Select(config, "t => t.GetNullableDecimalWithValue()").First(); - // Assert - Assert.Equal(100, result); - } + // Assert + Assert.Equal(100, result); } +} - class Test +class Test +{ + public decimal GetDecimal() { - public decimal GetDecimal() - { - return 42; - } + return 42; + } - public decimal? GetNullableDecimal() - { - return null; - } + public decimal? GetNullableDecimal() + { + return null; + } - public decimal? GetNullableDecimalWithValue() - { - return 100; - } + public decimal? GetNullableDecimalWithValue() + { + return 100; } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/SecurityTests.cs b/test/System.Linq.Dynamic.Core.Tests/SecurityTests.cs new file mode 100644 index 00000000..77fa0c76 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/SecurityTests.cs @@ -0,0 +1,67 @@ +using System.IO; +using System.Linq.Dynamic.Core.Exceptions; +using System.Net; +using System.Reflection; +using FluentAssertions; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests; + +public class SecurityTests +{ + class Message + { + public string Sender { get; } + public string Receiver { get; } + + public Message(string sender, string receiver) + { + Sender = sender; + Receiver = receiver; + } + } + + [Fact] + public void MethodsShouldOnlyBeCallableOnPredefinedTypes_Test1() + { + // Arrange + var baseQuery = new[] { 1, 2, 3 }.AsQueryable(); + string predicate = "\"\".GetType().Assembly.DefinedTypes.Where(it.name == \"Assembly\").First().DeclaredMethods.Where(it.Name == \"GetName\").First().Invoke(\"\".GetType().Assembly, new Object[] {} ).Name.ToString() != \"Test\""; + + // Act + Action action = () => baseQuery.OrderBy(predicate); + + // Assert + action.Should().Throw().WithMessage("Methods on type 'MethodBase' are not accessible"); + } + + [Fact] + public void MethodsShouldOnlyBeCallableOnPredefinedTypes_Test2() + { + // Arrange + var messages = new[] + { + new Message("Alice", "Bob"), + new Message("Bob", "Alice") + }.AsQueryable(); + + Action action = () => messages.Where( + "\"\".GetType().Assembly.GetType(\"System.AppDomain\").GetMethods()[104].Invoke(\"\".GetType().Assembly.GetType(\"System.AppDomain\").GetProperty(\"CurrentDomain\").GetValue(null), \"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;System.Diagnostics.Process\".Split(\";\".ToCharArray())).GetType().GetMethods()[80].Invoke(null, \"cmd;/T:4A /K whoami && echo was HACKED\".Split(\";\".ToCharArray()))" + ); + + // Assert + action.Should().Throw().WithMessage($"Methods on type 'Assembly' are not accessible"); + } + + [Theory] + [InlineData(typeof(FileStream), "Close()", "Stream")] + [InlineData(typeof(Assembly), "GetName().Name.ToString()", "Assembly")] + public void DynamicExpressionParser_ParseLambda_IllegalMethodCall_ThrowsException(Type itType, string expression, string type) + { + // Act + Action action = () => DynamicExpressionParser.ParseLambda(itType, null, expression); + + // Assert + action.Should().Throw().WithMessage($"Methods on type '{type}' are not accessible"); + } +} \ No newline at end of file From ff3e77ed37ac21135e71ae13fa526f5cbd7960e9 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 22 Feb 2023 18:20:23 +0100 Subject: [PATCH 033/214] Change default setting for PrioritizePropertyOrFieldOverTheType to 'true'. (#676) * Change default setting for PrioritizePropertyOrFieldOverTheType to 'true'. * tests --- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 373 ++++++++------- .../DynamicExpressionParserTests.cs | 16 +- .../ExpressionParserTests.TypeAccess.cs | 437 +++++++++--------- .../Parser/ExpressionParserTests.cs | 24 +- .../QueryableTests.Where.cs | 10 +- 5 files changed, 440 insertions(+), 420 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index 66f41fab..96f6d46c 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -4,221 +4,220 @@ using System.Linq.Dynamic.Core.CustomTypeProviders; using System.Linq.Dynamic.Core.Parser; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Configuration class for System.Linq.Dynamic.Core. +/// +public class ParsingConfig { /// - /// Configuration class for System.Linq.Dynamic.Core. + /// Default ParsingConfig /// - public class ParsingConfig + public static ParsingConfig Default { get; } = new ParsingConfig(); + + /// + /// Default ParsingConfig for EntityFramework Core 2.1 and higher + /// + public static ParsingConfig DefaultEFCore21 { get; } = new ParsingConfig { - /// - /// Default ParsingConfig - /// - public static ParsingConfig Default { get; } = new ParsingConfig(); - - /// - /// Default ParsingConfig for EntityFramework Core 2.1 and higher - /// - public static ParsingConfig DefaultEFCore21 { get; } = new ParsingConfig - { - EvaluateGroupByAtDatabase = true - }; + EvaluateGroupByAtDatabase = true + }; - /// Gets or sets if parameter, method, and properties resolution should be case sensitive or not (false by default). - public bool IsCaseSensitive { get; set; } + /// Gets or sets if parameter, method, and properties resolution should be case sensitive or not (false by default). + public bool IsCaseSensitive { get; set; } - /// - /// Default ParsingConfig for CosmosDb - /// - public static ParsingConfig DefaultCosmosDb { get; } = new ParsingConfig - { - RenameEmptyParameterExpressionNames = true - }; + /// + /// Default ParsingConfig for CosmosDb + /// + public static ParsingConfig DefaultCosmosDb { get; } = new ParsingConfig + { + RenameEmptyParameterExpressionNames = true + }; - private IDynamicLinkCustomTypeProvider? _customTypeProvider; + private IDynamicLinkCustomTypeProvider? _customTypeProvider; - private IExpressionPromoter? _expressionPromoter; + private IExpressionPromoter? _expressionPromoter; - private IQueryableAnalyzer? _queryableAnalyzer; + private IQueryableAnalyzer? _queryableAnalyzer; - /// - /// Gets or sets the . - /// - public IDynamicLinkCustomTypeProvider CustomTypeProvider + /// + /// Gets or sets the . + /// + public IDynamicLinkCustomTypeProvider CustomTypeProvider + { + get { - get - { #if !( WINDOWS_APP || UAP10_0 || NETSTANDARD) - // only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework and NET Core App 2.x - return _customTypeProvider ??= new DefaultDynamicLinqCustomTypeProvider(); + // only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework and NET Core App 2.x + return _customTypeProvider ??= new DefaultDynamicLinqCustomTypeProvider(); #else - return _customTypeProvider; + return _customTypeProvider; #endif - } + } - set + set + { + // ReSharper disable once RedundantCheckBeforeAssignment + if (_customTypeProvider != value) { - // ReSharper disable once RedundantCheckBeforeAssignment - if (_customTypeProvider != value) - { - _customTypeProvider = value; - } + _customTypeProvider = value; } } + } - /// - /// Gets or sets the . - /// - public IExpressionPromoter ExpressionPromoter - { - get => _expressionPromoter ??= new ExpressionPromoter(this); + /// + /// Gets or sets the . + /// + public IExpressionPromoter ExpressionPromoter + { + get => _expressionPromoter ??= new ExpressionPromoter(this); - set + set + { + // ReSharper disable once RedundantCheckBeforeAssignment + if (_expressionPromoter != value) { - // ReSharper disable once RedundantCheckBeforeAssignment - if (_expressionPromoter != value) - { - _expressionPromoter = value; - } + _expressionPromoter = value; } } + } - /// - /// Gets or sets the . - /// - public IQueryableAnalyzer QueryableAnalyzer + /// + /// Gets or sets the . + /// + public IQueryableAnalyzer QueryableAnalyzer + { + get { - get - { - return _queryableAnalyzer ??= new DefaultQueryableAnalyzer(); - } + return _queryableAnalyzer ??= new DefaultQueryableAnalyzer(); + } - set + set + { + // ReSharper disable once RedundantCheckBeforeAssignment + if (_queryableAnalyzer != value) { - // ReSharper disable once RedundantCheckBeforeAssignment - if (_queryableAnalyzer != value) - { - _queryableAnalyzer = value; - } + _queryableAnalyzer = value; } } - - /// - /// Determines if the context keywords (it, parent, and root) are valid and usable inside a Dynamic Linq string expression. - /// Does not affect the usability of the equivalent context symbols ($, ^ and ~). - /// - /// Default value is false. - /// - public bool AreContextKeywordsEnabled { get; set; } = true; - - /// - /// Gets or sets a value indicating whether the EntityFramework version supports evaluating GroupBy at database level. - /// See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation - /// - /// Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods. - /// - /// Default value is false. - /// - public bool EvaluateGroupByAtDatabase { get; set; } - - /// - /// Use Parameterized Names in generated dynamic SQL query. - /// See https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd - /// - /// Default value is false. - /// - public bool UseParameterizedNamesInDynamicQuery { get; set; } = false; - - /// - /// Allows the New() keyword to evaluate any available Type. - /// - /// Default value is false. - /// - public bool AllowNewToEvaluateAnyType { get; set; } = false; - - /// - /// Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from `it`. - /// - /// Default value is false. - /// - public bool RenameParameterExpression { get; set; } = false; - - /// - /// Prevents any System.Linq.Expressions.ParameterExpression.Name value from being empty by substituting a random 16 character word. - /// - /// Default value is false. - /// - public bool RenameEmptyParameterExpressionNames { get; set; } - - /// - /// By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use - /// this flag to disable this behaviour and have parsing fail when parsing an expression - /// where a member access on a non existing member happens. - /// - /// Default value is false. - /// - public bool DisableMemberAccessToIndexAccessorFallback { get; set; } = false; - - /// - /// By default finding types by a simple name is not supported. - /// Use this flag to use the CustomTypeProvider to resolve types by a simple name like "Employee" instead of "MyDatabase.Entities.Employee". - /// Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution. - /// - /// Default value is false. - /// - public bool ResolveTypesBySimpleName { get; set; } = false; - - /// - /// Support enumeration-types from the System namespace in mscorlib. An example could be "StringComparison". - /// - /// Default value is true. - /// - public bool SupportEnumerationsFromSystemNamespace { get; set; } = true; - - /// - /// By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. - /// Use this flag to parse all DateTime strings as UTC. - /// - /// Default value is false. - /// - public bool DateTimeIsParsedAsUTC { get; set; } = false; - - /// - /// The number parsing culture. - /// - /// Default value is CultureInfo.InvariantCulture - /// - public CultureInfo? NumberParseCulture { get; set; } = CultureInfo.InvariantCulture; - - /// - /// Additional TypeConverters - /// - public IDictionary? TypeConverters { get; set; } - - /// - /// When using the NullPropagating function np(...), use a "default value" for non-nullable value types instead of "null value". - /// - /// Default value is false. - /// - public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } = false; - - /// - /// Support casting to a full qualified type using a string (double quoted value). - /// - /// var result = queryable.Select($"\"System.DateTime\"(LastUpdate)"); - /// - /// - /// Default value is true. - /// - public bool SupportCastingToFullyQualifiedTypeAsString { get; set; } = true; - - /// - /// When the type and property have the same name the parser takes the property instead of type when this setting is set to true. - /// - /// The value from this setting should also be set to true when ExtensionMethods are used. - /// - /// Default value is false. - /// - public bool PrioritizePropertyOrFieldOverTheType { get; set; } } + + /// + /// Determines if the context keywords (it, parent, and root) are valid and usable inside a Dynamic Linq string expression. + /// Does not affect the usability of the equivalent context symbols ($, ^ and ~). + /// + /// Default value is false. + /// + public bool AreContextKeywordsEnabled { get; set; } = true; + + /// + /// Gets or sets a value indicating whether the EntityFramework version supports evaluating GroupBy at database level. + /// See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation + /// + /// Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods. + /// + /// Default value is false. + /// + public bool EvaluateGroupByAtDatabase { get; set; } + + /// + /// Use Parameterized Names in generated dynamic SQL query. + /// See https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd + /// + /// Default value is false. + /// + public bool UseParameterizedNamesInDynamicQuery { get; set; } = false; + + /// + /// Allows the New() keyword to evaluate any available Type. + /// + /// Default value is false. + /// + public bool AllowNewToEvaluateAnyType { get; set; } = false; + + /// + /// Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from `it`. + /// + /// Default value is false. + /// + public bool RenameParameterExpression { get; set; } = false; + + /// + /// Prevents any System.Linq.Expressions.ParameterExpression.Name value from being empty by substituting a random 16 character word. + /// + /// Default value is false. + /// + public bool RenameEmptyParameterExpressionNames { get; set; } + + /// + /// By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use + /// this flag to disable this behaviour and have parsing fail when parsing an expression + /// where a member access on a non existing member happens. + /// + /// Default value is false. + /// + public bool DisableMemberAccessToIndexAccessorFallback { get; set; } = false; + + /// + /// By default finding types by a simple name is not supported. + /// Use this flag to use the CustomTypeProvider to resolve types by a simple name like "Employee" instead of "MyDatabase.Entities.Employee". + /// Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution. + /// + /// Default value is false. + /// + public bool ResolveTypesBySimpleName { get; set; } = false; + + /// + /// Support enumeration-types from the System namespace in mscorlib. An example could be "StringComparison". + /// + /// Default value is true. + /// + public bool SupportEnumerationsFromSystemNamespace { get; set; } = true; + + /// + /// By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. + /// Use this flag to parse all DateTime strings as UTC. + /// + /// Default value is false. + /// + public bool DateTimeIsParsedAsUTC { get; set; } = false; + + /// + /// The number parsing culture. + /// + /// Default value is CultureInfo.InvariantCulture + /// + public CultureInfo? NumberParseCulture { get; set; } = CultureInfo.InvariantCulture; + + /// + /// Additional TypeConverters + /// + public IDictionary? TypeConverters { get; set; } + + /// + /// When using the NullPropagating function np(...), use a "default value" for non-nullable value types instead of "null value". + /// + /// Default value is false. + /// + public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } = false; + + /// + /// Support casting to a full qualified type using a string (double quoted value). + /// + /// var result = queryable.Select($"\"System.DateTime\"(LastUpdate)"); + /// + /// + /// Default value is true. + /// + public bool SupportCastingToFullyQualifiedTypeAsString { get; set; } = true; + + /// + /// When the type and property have the same name the parser takes the property instead of type when this setting is set to true. + /// + /// This setting is also used for calling ExtensionMethods. + /// + /// Default value is true. + /// + public bool PrioritizePropertyOrFieldOverTheType { get; set; } = true; } \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 83d99980..17309c5b 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -1082,6 +1082,20 @@ public void DynamicExpressionParser_ParseLambda_With_DateTime_Equals_String() Assert.True(result); } + [Fact] + public void DynamicExpressionParser_ParseLambda_With_DateTime_UtcNow_AddHours_ToString_Issue675() + { + // Arrange + var expressionText = "DateTime.UtcNow.AddHours(2).ToString(\"o\")"; + var parameterExpression = Expression.Parameter(typeof(string)); + + // Act + var lambda = DynamicExpressionParser.ParseLambda(new[] { parameterExpression }, typeof(object), expressionText); + + // Assert + lambda.Should().NotBeNull(); + } + [Fact] public void DynamicExpressionParser_ParseLambda_With_Guid_Equals_String() { @@ -1459,7 +1473,7 @@ public void DynamicExpressionParser_ParseLambda_String_TrimEnd_1_Parameter() result.Should().BeTrue(); } - public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider + public class DefaultDynamicLinqCustomTypeProviderForGenericExtensionMethod : DefaultDynamicLinqCustomTypeProvider { public override HashSet GetCustomTypes() => new HashSet(base.GetCustomTypes()) { typeof(Methods), typeof(MethodsItemExtension) }; } diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs index 0129e36e..9c92c1b3 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.TypeAccess.cs @@ -4,229 +4,228 @@ using FluentAssertions; using Xunit; -namespace System.Linq.Dynamic.Core.Tests.Parser +namespace System.Linq.Dynamic.Core.Tests.Parser; + +partial class ExpressionParserTests { - partial class ExpressionParserTests + [Fact] + public void ParseTypeAccess_Via_Constructor_CharAndInt_To_String() + { + // Arrange + var parameter = Expression.Parameter(typeof(string)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, "string('c', 3)", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(string)); + + // Assert + expression.ToString().Should().Be("new String(c, 3)"); + } + + [Theory] + [InlineData(123, "new DateTime(123)")] + [InlineData(633979008000000000, "new DateTime(633979008000000000)")] + public void ParseTypeAccess_Via_Constructor_Ticks_To_DateTime(object ticks, string result) + { + // Arrange + var parameter = Expression.Parameter(typeof(DateTime)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateTime({ticks})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateTime)); + + // Assert + expression.ToString().Should().Be(result); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_String_To_DateTime_Valid() + { + // Arrange + string str = "\"2020-10-31 09:15:11\""; + var parameter = Expression.Parameter(typeof(DateTime)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateTime({str})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateTime)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_Arguments_To_DateTime_Valid() { - [Fact] - public void ParseTypeAccess_Via_Constructor_CharAndInt_To_String() - { - // Arrange - var parameter = Expression.Parameter(typeof(string)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"string('c', 3)", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(string)); - - // Assert - expression.ToString().Should().Be("new String(c, 3)"); - } - - [Theory] - [InlineData(123, "new DateTime(123)")] - [InlineData(633979008000000000, "new DateTime(633979008000000000)")] - public void ParseTypeAccess_Via_Constructor_Ticks_To_DateTime(object ticks, string result) - { - // Arrange - var parameter = Expression.Parameter(typeof(DateTime)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateTime({ticks})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(DateTime)); - - // Assert - expression.ToString().Should().Be(result); - } - - [Fact] - public void ParseTypeAccess_Via_Constructor_String_To_DateTime_Valid() - { - // Arrange - string str = "\"2020-10-31 09:15:11\""; - var parameter = Expression.Parameter(typeof(DateTime)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateTime({str})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(DateTime)); - - // Assert - expression.ToString().Should().NotBeEmpty(); - } - - [Fact] - public void ParseTypeAccess_Via_Constructor_Arguments_To_DateTime_Valid() - { - // Arrange - var arguments = "2022, 10, 31, 9, 15, 11"; - var parameter = Expression.Parameter(typeof(DateTime)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateTime({arguments})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(DateTime)); - - // Assert - expression.ToString().Should().NotBeEmpty(); - } - - [Theory] - [InlineData(null)] - [InlineData("\"abc\"")] - public void ParseTypeAccess_Via_Constructor_Any_To_DateTime_Invalid(object any) - { - // Arrange - var parameter = Expression.Parameter(typeof(DateTime)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateTime({any})", new object[] { }, ParsingConfig.Default); - Action a = () => parser.Parse(typeof(DateTime)); - - // Assert - a.Should().Throw(); - } + // Arrange + var arguments = "2022, 10, 31, 9, 15, 11"; + var parameter = Expression.Parameter(typeof(DateTime)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateTime({arguments})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateTime)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Theory] + [InlineData(null)] + [InlineData("\"abc\"")] + public void ParseTypeAccess_Via_Constructor_Any_To_DateTime_Invalid(object any) + { + // Arrange + var parameter = Expression.Parameter(typeof(DateTime)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateTime({any})", new object[] { }, ParsingConfig.Default); + Action a = () => parser.Parse(typeof(DateTime)); + + // Assert + a.Should().Throw(); + } #if NET6_0_OR_GREATER - [Fact] - public void ParseTypeAccess_Via_Constructor_String_To_DateOnly_Valid() - { - // Arrange - string str = "\"2020-10-31\""; - var parameter = Expression.Parameter(typeof(DateOnly)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({str})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(DateOnly)); - - // Assert - expression.ToString().Should().NotBeEmpty(); - } - - [Fact] - public void ParseTypeAccess_Via_Constructor_Arguments_To_DateOnly_Valid() - { - // Arrange - var arguments = "2022, 10, 31"; - var parameter = Expression.Parameter(typeof(DateOnly)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({arguments})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(DateOnly)); - - // Assert - expression.ToString().Should().NotBeEmpty(); - } - - [Theory] - [InlineData(null)] - [InlineData("\"abc\"")] - public void ParseTypeAccess_Via_Constructor_Any_To_DateOnly_Invalid(object any) - { - // Arrange - var parameter = Expression.Parameter(typeof(DateOnly)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({any})", new object[] { }, ParsingConfig.Default); - Action a = () => parser.Parse(typeof(DateOnly)); - - // Assert - a.Should().Throw(); - } - - [Fact] - public void ParseTypeAccess_Via_Constructor_String_To_TimeOnly_Valid() - { - // Arrange - string str = "\"09:15:11\""; - var parameter = Expression.Parameter(typeof(TimeOnly)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({str})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(TimeOnly)); - - // Assert - expression.ToString().Should().NotBeEmpty(); - } - - [Fact] - public void ParseTypeAccess_Via_Constructor_Arguments_To_TimeOnly_Valid() - { - // Arrange - var arguments = "9, 15, 11"; - var parameter = Expression.Parameter(typeof(TimeOnly)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({arguments})", new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(TimeOnly)); - - // Assert - expression.ToString().Should().NotBeEmpty(); - } - - [Theory] - [InlineData(null)] - [InlineData("\"abc\"")] - public void ParseTypeAccess_Via_Constructor_Any_To_TimeOnly_Invalid(object any) - { - // Arrange - var parameter = Expression.Parameter(typeof(TimeOnly)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({any})", new object[] { }, ParsingConfig.Default); - Action a = () => parser.Parse(typeof(TimeOnly)); - - // Assert - a.Should().Throw(); - } + [Fact] + public void ParseTypeAccess_Via_Constructor_String_To_DateOnly_Valid() + { + // Arrange + string str = "\"2020-10-31\""; + var parameter = Expression.Parameter(typeof(DateOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({str})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_Arguments_To_DateOnly_Valid() + { + // Arrange + var arguments = "2022, 10, 31"; + var parameter = Expression.Parameter(typeof(DateOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({arguments})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(DateOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Theory] + [InlineData(null)] + [InlineData("\"abc\"")] + public void ParseTypeAccess_Via_Constructor_Any_To_DateOnly_Invalid(object any) + { + // Arrange + var parameter = Expression.Parameter(typeof(DateOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"DateOnly({any})", new object[] { }, ParsingConfig.Default); + Action a = () => parser.Parse(typeof(DateOnly)); + + // Assert + a.Should().Throw(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_String_To_TimeOnly_Valid() + { + // Arrange + string str = "\"09:15:11\""; + var parameter = Expression.Parameter(typeof(TimeOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({str})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(TimeOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_Arguments_To_TimeOnly_Valid() + { + // Arrange + var arguments = "9, 15, 11"; + var parameter = Expression.Parameter(typeof(TimeOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({arguments})", new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(TimeOnly)); + + // Assert + expression.ToString().Should().NotBeEmpty(); + } + + [Theory] + [InlineData(null)] + [InlineData("\"abc\"")] + public void ParseTypeAccess_Via_Constructor_Any_To_TimeOnly_Invalid(object any) + { + // Arrange + var parameter = Expression.Parameter(typeof(TimeOnly)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, $"TimeOnly({any})", new object[] { }, ParsingConfig.Default); + Action a = () => parser.Parse(typeof(TimeOnly)); + + // Assert + a.Should().Throw(); + } #endif - [Fact] - public void ParseTypeAccess_Via_Constructor_String_To_Uri() - { - // Arrange - string selector = "Uri(\"https://www.example.com/\")"; - var parameter = Expression.Parameter(typeof(Uri)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, selector, new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(Uri)); - - // Assert - expression.ToString().Should().Be("https://www.example.com/"); - } - - [Fact] - public void ParseTypeAccess_Via_Constructor_String_And_UriKind_To_Uri() - { - // Arrange - string selector = "Uri(\"https://www.example.com/\", UriKind.Absolute)"; - var parameter = Expression.Parameter(typeof(Uri)); - - // Act - var parser = new ExpressionParser(new[] { parameter }, selector, new object[] { }, ParsingConfig.Default); - var expression = parser.Parse(typeof(Uri)); - - // Assert - expression.ToString().Should().Be("new Uri(\"https://www.example.com/\", Absolute)"); - } - - [Theory] - [InlineData("new(1 as a, 2 as b)", "new*(a = 1, b = 2)")] - [InlineData("new(2 as b, 1 as a)", "new*(a = 1, b = 2)")] - public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpression, string newExpression2) - { - // Arrange - var parameter = Expression.Parameter(typeof(int)); - var parameter2 = Expression.Parameter(typeof(int)); - var returnType = DynamicClassFactory.CreateType(new List { - new DynamicProperty("a", typeof(int)), - new DynamicProperty("b", typeof(int)) - }); - - // Act - var parser = new ExpressionParser(new[] { parameter, parameter2 }, newExpression, new object[] { }, ParsingConfig.Default); - - var expression = parser.Parse(returnType); - // Assert - expression.ToString().Should().Match(newExpression2); - } + [Fact] + public void ParseTypeAccess_Via_Constructor_String_To_Uri() + { + // Arrange + string selector = "Uri(\"https://www.example.com/\")"; + var parameter = Expression.Parameter(typeof(Uri)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, selector, new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(Uri)); + + // Assert + expression.ToString().Should().Be("https://www.example.com/"); + } + + [Fact] + public void ParseTypeAccess_Via_Constructor_String_And_UriKind_To_Uri() + { + // Arrange + string selector = "Uri(\"https://www.example.com/\", UriKind.Absolute)"; + var parameter = Expression.Parameter(typeof(Uri)); + + // Act + var parser = new ExpressionParser(new[] { parameter }, selector, new object[] { }, ParsingConfig.Default); + var expression = parser.Parse(typeof(Uri)); + + // Assert + expression.ToString().Should().Be("new Uri(\"https://www.example.com/\", Absolute)"); + } + + [Theory] + [InlineData("new(1 as a, 2 as b)", "new*(a = 1, b = 2)")] + [InlineData("new(2 as b, 1 as a)", "new*(a = 1, b = 2)")] + public void ParseTypeAccess_Via_Constructor_DynamicType_To_String(string newExpression, string newExpression2) + { + // Arrange + var parameter = Expression.Parameter(typeof(int)); + var parameter2 = Expression.Parameter(typeof(int)); + var returnType = DynamicClassFactory.CreateType(new List { + new DynamicProperty("a", typeof(int)), + new DynamicProperty("b", typeof(int)) + }); + + // Act + var parser = new ExpressionParser(new[] { parameter, parameter2 }, newExpression, new object[] { }, ParsingConfig.Default); + + var expression = parser.Parse(returnType); + // Assert + expression.ToString().Should().Match(newExpression2); } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs index b32c151c..d246327a 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs @@ -172,9 +172,9 @@ public void Parse_CastStringIntShouldReturnConstantExpression(string expression, [Theory] #if NET452 - [InlineData("int?(5)", typeof(int?), "Convert(5)")] - [InlineData("int?(null)", typeof(int?), "Convert(null)")] - [InlineData("string(null)", typeof(string), "Convert(null)")] + [InlineData("int?(5)", typeof(int?), "Convert(5)")] + [InlineData("int?(null)", typeof(int?), "Convert(null)")] + [InlineData("string(null)", typeof(string), "Convert(null)")] #else [InlineData("int?(5)", typeof(int?), "Convert(5, Nullable`1)")] [InlineData("int?(null)", typeof(int?), "Convert(null, Nullable`1)")] @@ -199,15 +199,14 @@ public void Parse_NullableShouldReturnNullable(string expression, object resultT [InlineData("@MainCompany.Companies.Count() > 0", "(company.MainCompany.Companies.Count() > 0)")] [InlineData("Company.Equals(null, null)", "Equals(null, null)")] [InlineData("MainCompany.Name", "company.MainCompany.Name")] - [InlineData("Company.Name", "No property or field 'Name' exists in type 'Company'")] + [InlineData("Name", "company.Name")] [InlineData("DateTime", "company.DateTime")] public void Parse_When_PrioritizePropertyOrFieldOverTheType_IsTrue(string expression, string result) { // Arrange var config = new ParsingConfig { - CustomTypeProvider = _dynamicTypeProviderMock.Object, - PrioritizePropertyOrFieldOverTheType = true + CustomTypeProvider = _dynamicTypeProviderMock.Object }; ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "company") }; var sut = new ExpressionParser(parameters, expression, null, config); @@ -230,20 +229,25 @@ public void Parse_When_PrioritizePropertyOrFieldOverTheType_IsTrue(string expres [Theory] [InlineData("it.MainCompany.Name != null", "(company.MainCompany.Name != null)")] [InlineData("@MainCompany.Companies.Count() > 0", "(company.MainCompany.Companies.Count() > 0)")] - [InlineData("Company.Equals(null, null)", "Equals(null, null)")] - [InlineData("MainCompany.Name", "Static property requires null instance, non-static property requires non-null instance.")] // Exception + [InlineData("Company.Equals(null, null)", "No applicable method 'Equals' exists in type 'Company'")] // Exception + [InlineData("MainCompany.Name", "company.MainCompany.Name")] + [InlineData("Name", "company.Name")] + [InlineData("it.DateTime", "company.DateTime")] [InlineData("DateTime", "'.' or '(' or string literal expected")] // Exception - [InlineData("Company.Name", "Static property requires null instance, non-static property requires non-null instance.")] // Exception public void Parse_When_PrioritizePropertyOrFieldOverTheType_IsFalse(string expression, string result) { // Arrange + var config = new ParsingConfig + { + PrioritizePropertyOrFieldOverTheType = false + }; ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(Company), "company") }; // Act string parsedExpression; try { - var sut = new ExpressionParser(parameters, expression, null, _parsingConfig); + var sut = new ExpressionParser(parameters, expression, null, config); parsedExpression = sut.Parse(null).ToString(); } catch (Exception e) diff --git a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs index 5a340319..0e48885f 100644 --- a/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs +++ b/test/System.Linq.Dynamic.Core.Tests/QueryableTests.Where.cs @@ -281,6 +281,10 @@ public void Where_Dynamic_ExpandoObject_As_AnonymousType() public void Where_Dynamic_DateTimeConstructor_Issue662() { // Arrange + var config = new ParsingConfig + { + PrioritizePropertyOrFieldOverTheType = false + }; var date = new DateTime(2023, 1, 13, 12, 0, 0); var queryable = new List { @@ -289,13 +293,13 @@ public void Where_Dynamic_DateTimeConstructor_Issue662() }.AsQueryable(); // Act 1 - //var result1 = queryable.Where("DT > DateTime(2022, 1, 1, 0, 0, 0)").ToArray(); + var result1 = queryable.Where(config, "DT > DateTime(2022, 1, 1, 0, 0, 0)").ToArray(); // Assert 1 - //result1.Should().HaveCount(1); + result1.Should().HaveCount(1); // Act 2 - var result2 = queryable.Where("it.DateTime > DateTime(2022, 1, 1, 0, 0, 0)").ToArray(); + var result2 = queryable.Where(config, "it.DateTime > DateTime(2022, 1, 1, 0, 0, 0)").ToArray(); // Assert 2 result2.Should().HaveCount(1); From 93e0c8c45c21c70448b86cf97b3065973c70c879 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 3 Mar 2023 19:36:29 +0100 Subject: [PATCH 034/214] v1.3.0 + generate docs --- CHANGELOG.md | 12 + Generate-ReleaseNotes.bat | 2 +- docfx/howto.txt | 2 +- ...AbstractDynamicLinqCustomTypeProvider.html | 81 +- ....DefaultDynamicLinqCustomTypeProvider.html | 125 +- ...ypeProviders.DynamicLinqTypeAttribute.html | 117 +- ...viders.IDynamicLinkCustomTypeProvider.html | 167 +- ...viders.IDynamicLinqCustomTypeProvider.html | 303 ++ ...Linq.Dynamic.Core.CustomTypeProviders.html | 15 +- ...Dynamic.Core.DefaultQueryableAnalyzer.html | 53 +- ...System.Linq.Dynamic.Core.DynamicClass.html | 57 +- ...Linq.Dynamic.Core.DynamicClassFactory.html | 97 +- ...amic.Core.DynamicEnumerableExtensions.html | 121 +- ....Dynamic.Core.DynamicExpressionParser.html | 1132 ++++- ...tem.Linq.Dynamic.Core.DynamicProperty.html | 49 +- ...namic.Core.DynamicQueryableExtensions.html | 4503 ++++++++++++----- ...ynamic.Core.Exceptions.ParseException.html | 95 +- .../System.Linq.Dynamic.Core.Exceptions.html | 9 +- ....Linq.Dynamic.Core.ExtensibilityPoint.html | 35 +- .../System.Linq.Dynamic.Core.GroupResult.html | 63 +- ...tem.Linq.Dynamic.Core.IAssemblyHelper.html | 19 +- ....Linq.Dynamic.Core.IQueryableAnalyzer.html | 25 +- ...ystem.Linq.Dynamic.Core.PagedResult-1.html | 35 +- .../System.Linq.Dynamic.Core.PagedResult.html | 59 +- ....Dynamic.Core.Parser.ExpressionParser.html | 65 +- ...ynamic.Core.Parser.ExpressionPromoter.html | 70 +- ...namic.Core.Parser.IExpressionPromoter.html | 31 +- ...Linq.Dynamic.Core.Parser.NumberParser.html | 217 +- docs/api/System.Linq.Dynamic.Core.Parser.html | 12 +- ...ystem.Linq.Dynamic.Core.ParsingConfig.html | 332 +- ...inq.Dynamic.Core.Tokenizer.TextParser.html | 328 ++ ...tem.Linq.Dynamic.Core.Tokenizer.Token.html | 284 ++ ...m.Linq.Dynamic.Core.Tokenizer.TokenId.html | 305 ++ .../System.Linq.Dynamic.Core.Tokenizer.html | 139 + docs/api/System.Linq.Dynamic.Core.html | 13 +- docs/api/System.Tuple-2.html | 251 + docs/api/System.html | 129 + docs/api/toc.html | 29 + docs/index.html | 9 +- docs/index.json | 219 +- docs/manifest.json | 152 +- docs/styles/docfx.css | 74 +- docs/styles/docfx.js | 98 +- docs/styles/docfx.vendor.css | 599 ++- docs/styles/docfx.vendor.js | 56 +- docs/styles/lunr.min.js | 2 +- docs/styles/search-worker.js | 2 +- docs/toc.html | 2 +- docs/xrefmap.yml | 1022 +++- .../EntityFramework.DynamicLinq.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore2.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore3.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore5.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore6.csproj | 2 +- ...tyFrameworkCore.DynamicLinq.EFCore7.csproj | 2 +- .../System.Linq.Dynamic.Core.csproj | 2 +- ...EntityFramework.Classic.DynamicLinq.csproj | 2 +- version.xml | 2 +- 58 files changed, 8741 insertions(+), 2893 deletions(-) create mode 100644 docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html create mode 100644 docs/api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html create mode 100644 docs/api/System.Linq.Dynamic.Core.Tokenizer.Token.html create mode 100644 docs/api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html create mode 100644 docs/api/System.Linq.Dynamic.Core.Tokenizer.html create mode 100644 docs/api/System.Tuple-2.html create mode 100644 docs/api/System.html diff --git a/CHANGELOG.md b/CHANGELOG.md index f02fb429..0cbdeb3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# v1.3.0 (03 March 2023) +- [#669](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/669) - Methods should only be callable on predefined types [security] contributed by [StefH](https://github.com/StefH) +- [#671](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/671) - Add support for DateOnly and TimeOnly [feature] contributed by [StefH](https://github.com/StefH) +- [#672](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/672) - Fixed ExpressionParser when WrappedValue-string is used for equals-operator for Enum [bug] contributed by [StefH](https://github.com/StefH) +- [#674](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/674) - Stef 668 enum string wrapped contributed by [neilbgr](https://github.com/neilbgr) +- [#676](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/676) - Change default setting for PrioritizePropertyOrFieldOverTheType to 'true'. [bug] contributed by [StefH](https://github.com/StefH) +- [#651](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/651) - Selecting shadow properties +- [#661](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/661) - Question on projection of child object properties in a Select. +- [#667](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/667) - DateOnly support [feature] +- [#668](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/668) - With UseParameterizedNamesInDynamicQuery, can't compare enum type with String [bug] +- [#675](https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/675) - Expression does not parse any more 1.2.25 (works in 1.2.24) [bug] + # v1.2.25 (05 February 2023) - [#664](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/664) - Add config setting for PrioritizePropertyOrFieldOverTheType [feature] contributed by [StefH](https://github.com/StefH) - [#665](https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/665) - Update AbstractDynamicLinqCustomTypeProvider to exclude null types [bug] contributed by [StefH](https://github.com/StefH) diff --git a/Generate-ReleaseNotes.bat b/Generate-ReleaseNotes.bat index b370cd6a..f7d133e1 100644 --- a/Generate-ReleaseNotes.bat +++ b/Generate-ReleaseNotes.bat @@ -1,5 +1,5 @@ rem https://github.com/StefH/GitHubReleaseNotes -SET version=v1.2.25 +SET version=v1.3.0 GitHubReleaseNotes --output CHANGELOG.md --exclude-labels invalid question documentation wontfix --language en --version %version% --token %GH_TOKEN% diff --git a/docfx/howto.txt b/docfx/howto.txt index 82658ff3..209f7559 100644 --- a/docfx/howto.txt +++ b/docfx/howto.txt @@ -1,3 +1,3 @@ 1. choco install docfx -y -2. Run powershell script: build-docs.ps1 -serve +2. Run powershell script: ./build-docs.ps1 -serve diff --git a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html index 7ad421a5..815a4cd4 100644 --- a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html +++ b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
-
+
Search Results for

-
    +
      Inheritance
      - +
      AbstractDynamicLinqCustomTypeProvider
      Namespace: System.Linq.Dynamic.Core.CustomTypeProviders
      @@ -126,10 +126,10 @@

      Methods

      | - Improve this Doc + Improve this Doc - View Source + View Source

      FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable<Assembly>)

      @@ -138,7 +138,7 @@

      Declaration
      -
      protected IEnumerable<Type> FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull] IEnumerable<Assembly> assemblies)
      +
      protected IEnumerable<Type> FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable<Assembly> assemblies)
      Parameters
      @@ -151,7 +151,7 @@
      Parameters
      - + @@ -168,18 +168,18 @@
      Returns
      - - +
      IEnumerable<Assembly>IEnumerable<Assembly> assemblies

      The assemblies to process.

      IEnumerable<Type>

      IEnumerable<T>

      +
      IEnumerable<Type>

      IEnumerable<T>

      | - Improve this Doc + Improve this Doc - View Source + View Source

      GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable<Assembly>)

      @@ -188,7 +188,7 @@

      Declaration
      -
      protected IEnumerable<Type> GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable<Assembly> assemblies)
      +
      protected IEnumerable<Type> GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable<Assembly> assemblies)
      Parameters
      @@ -201,7 +201,7 @@
      Parameters
      - + @@ -218,18 +218,18 @@
      Returns
      - - +
      IEnumerable<Assembly>IEnumerable<Assembly> assemblies

      The assemblies to process.

      IEnumerable<Type>

      IEnumerable<T>

      +
      IEnumerable<Type>

      IEnumerable<T>

      | - Improve this Doc + Improve this Doc - View Source + View Source

      ResolveType(IEnumerable<Assembly>, String)

      @@ -238,7 +238,7 @@

      Declaration
      -
      protected Type ResolveType([NotNull] IEnumerable<Assembly> assemblies, [NotNull] string typeName)
      +
      protected Type ResolveType(IEnumerable<Assembly> assemblies, string typeName)
      Parameters
      @@ -251,13 +251,13 @@
      Parameters
      - + - + @@ -274,18 +274,18 @@
      Returns
      - - +
      IEnumerable<Assembly>IEnumerable<Assembly> assemblies

      The assemblies to inspect.

      StringString typeName

      The typename to resolve.

      Type

      A resolved Type or null when not found.

      +
      Type

      A resolved Type or null when not found.

      | - Improve this Doc + Improve this Doc - View Source + View Source

      ResolveTypeBySimpleName(IEnumerable<Assembly>, String)

      @@ -294,7 +294,7 @@

      Declaration
      -
      protected Type ResolveTypeBySimpleName([NotNull] IEnumerable<Assembly> assemblies, [NotNull] string simpleTypeName)
      +
      protected Type ResolveTypeBySimpleName(IEnumerable<Assembly> assemblies, string simpleTypeName)
      Parameters
      @@ -307,13 +307,13 @@
      Parameters
      - + - + @@ -330,8 +330,8 @@
      Returns
      - - + @@ -344,15 +344,16 @@
      Returns
      diff --git a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html index 03c9bbbb..60656171 100644 --- a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html +++ b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
      -
      +
      Search Results for

      -
        +
          - + - @@ -181,14 +182,15 @@

          Methods

          | - Improve this Doc + Improve this Doc - View Source + View Source

          GetCustomTypes()

          -
          +

          Returns a list of custom types that System.Linq.Dynamic.Core will understand.

          +
          Declaration
          @@ -204,21 +206,55 @@
          Returns
          - - + + + + +
          IEnumerable<Assembly>IEnumerable<Assembly> assemblies

          The assemblies to inspect.

          StringString simpleTypeName

          The simple typename to resolve.

          Type

          A resolved Type or null when not found.

          +
          Type

          A resolved Type or null when not found.

          BooleanBoolean cacheCustomTypes

          Defines whether to cache the CustomTypes which are found in the Application Domain. Default set to 'true'.

          +

          Defines whether to cache the CustomTypes (including extension methods) which are found in the Application Domain. Default set to 'true'.

          HashSet<Type>HashSet<Type>

          A HashSet<T> list of custom types.

          +
          + + | + Improve this Doc + + + View Source + + +

          GetExtensionMethods()

          +

          Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand.

          +
          +
          +
          Declaration
          +
          +
          public Dictionary<Type, List<MethodInfo>> GetExtensionMethods()
          +
          +
          Returns
          + + + + + + + + + + +
          TypeDescription
          Dictionary<Type, List<MethodInfo>>

          A list of custom extension methods that System.Linq.Dynamic.Core will understand.

          +
          | - Improve this Doc + Improve this Doc - View Source + View Source

          ResolveType(String)

          -
          +

          Resolve any type by fullname which is registered in the current application domain.

          +
          Declaration
          @@ -235,9 +271,10 @@
          Parameters
          - String + String typeName - +

          The typename to resolve.

          + @@ -251,21 +288,23 @@
          Returns
          - Type - + Type +

          A resolved Type or null when not found.

          + | - Improve this Doc + Improve this Doc - View Source + View Source

          ResolveTypeBySimpleName(String)

          -
          +

          Resolve any type by the simple name which is registered in the current application domain.

          +
          Declaration
          @@ -282,9 +321,10 @@
          Parameters
          - String + String simpleTypeName - +

          The typename to resolve.

          + @@ -298,8 +338,9 @@
          Returns
          - Type - + Type +

          A resolved Type or null when not found.

          + @@ -307,6 +348,9 @@

          Implements

          +
          @@ -315,15 +359,16 @@

          Implements

          diff --git a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html index ec24ee5a..5c5a5bbc 100644 --- a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html +++ b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
          -
          +
          Search Results for

          -
            +
              Inheritance
              - - + +
              DynamicLinqTypeAttribute
              -
              +
              Implements
              - +
              Inherited Members
              Namespace: System.Linq.Dynamic.Core.CustomTypeProviders
              Assembly: System.Linq.Dynamic.Core.dll
              Syntax
              -
              [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
              +    
              [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
               public sealed class DynamicLinqTypeAttribute : Attribute, _Attribute

              Implements

              @@ -256,15 +256,16 @@

              Implements

              diff --git a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html index eeb933eb..b78f6b3d 100644 --- a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html +++ b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
              -
              +
              Search Results for

              -
                +
                  diff --git a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html new file mode 100644 index 00000000..b0b7f031 --- /dev/null +++ b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html @@ -0,0 +1,303 @@ + + + + + + + + Interface IDynamicLinqCustomTypeProvider + + + + + + + + + + + + + + + + +
                  +
                  + + + + +
                  +
                  + +
                  +
                  Search Results for
                  +
                  +

                  +
                  +
                    +
                    +
                    + + + +
                    + + + + + + diff --git a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.html b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.html index 2aabbd59..dbe11daf 100644 --- a/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.html +++ b/docs/api/System.Linq.Dynamic.Core.CustomTypeProviders.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                    -
                    +
                    Search Results for

                    -
                      +
                        diff --git a/docs/api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html b/docs/api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html index 83a4de51..66ce87d3 100644 --- a/docs/api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html +++ b/docs/api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                        -
                        +
                        Search Results for

                        -
                          +
                            Inheritance
                            -
                            +
                            DefaultQueryableAnalyzer
                            -
                            +
                            Implements
                            Namespace: System.Linq.Dynamic.Core
                            @@ -129,14 +129,15 @@

                            Methods

                            | - Improve this Doc + Improve this Doc - View Source + View Source

                            SupportsLinqToObjects(IQueryable, IQueryProvider)

                            -
                            +

                            Determines whether the specified query (and provider) supports LinqToObjects.

                            +
                            Declaration
                            @@ -153,14 +154,16 @@
                            Parameters
                            - IQueryable + IQueryable query - +

                            The query to check.

                            + - IQueryProvider + IQueryProvider provider - +

                            The provider to check (can be null).

                            + @@ -174,8 +177,9 @@
                            Returns
                            - Boolean - + Boolean +

                            true/false

                            + @@ -195,15 +199,16 @@

                            See Also

                            diff --git a/docs/api/System.Linq.Dynamic.Core.DynamicClass.html b/docs/api/System.Linq.Dynamic.Core.DynamicClass.html index 31d0077d..60696707 100644 --- a/docs/api/System.Linq.Dynamic.Core.DynamicClass.html +++ b/docs/api/System.Linq.Dynamic.Core.DynamicClass.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                            -
                            +
                            Search Results for

                            -
                              +
                                Inheritance
                                - +
                                DynamicClass
                                Namespace: System.Linq.Dynamic.Core
                                @@ -125,10 +125,10 @@

                                Methods

                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                GetDynamicPropertyValue(String)

                                @@ -150,7 +150,7 @@
                                Parameters
                                - String + String propertyName

                                Name of the property.

                                @@ -167,7 +167,7 @@
                                Returns
                                - Object + Object

                                value

                                @@ -175,10 +175,10 @@
                                Returns
                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                GetDynamicPropertyValue<T>(String)

                                @@ -200,7 +200,7 @@
                                Parameters
                                - String + String propertyName

                                Name of the property.

                                @@ -241,10 +241,10 @@
                                Type Parameters
                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                SetDynamicPropertyValue(String, Object)

                                @@ -266,13 +266,13 @@
                                Parameters
                                - String + String propertyName

                                Name of the property.

                                - Object + Object value

                                The value.

                                @@ -281,10 +281,10 @@
                                Parameters
                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                SetDynamicPropertyValue<T>(String, T)

                                @@ -306,7 +306,7 @@
                                Parameters
                                - String + String propertyName

                                Name of the property.

                                @@ -343,15 +343,16 @@
                                Type Parameters
                                diff --git a/docs/api/System.Linq.Dynamic.Core.DynamicClassFactory.html b/docs/api/System.Linq.Dynamic.Core.DynamicClassFactory.html index 1fabf250..c04be03a 100644 --- a/docs/api/System.Linq.Dynamic.Core.DynamicClassFactory.html +++ b/docs/api/System.Linq.Dynamic.Core.DynamicClassFactory.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                -
                                +
                                Search Results for

                                -
                                  +
                                    Inheritance
                                    - +
                                    DynamicClassFactory
                                    Namespace: System.Linq.Dynamic.Core
                                    @@ -125,10 +125,66 @@

                                    Methods

                                    | - Improve this Doc + Improve this Doc - View Source + View Source + + +

                                    CreateGenericComparerType(Type, Type)

                                    +

                                    Create a GenericComparerType based on the GenericType and an instance of a IComparer.

                                    +
                                    +
                                    +
                                    Declaration
                                    +
                                    +
                                    public static Type CreateGenericComparerType(Type comparerGenericType, Type comparerType)
                                    +
                                    +
                                    Parameters
                                    + + + + + + + + + + + + + + + + + + + + +
                                    TypeNameDescription
                                    TypecomparerGenericType

                                    The GenericType

                                    +
                                    TypecomparerType

                                    The IComparer instance

                                    +
                                    +
                                    Returns
                                    + + + + + + + + + + + + + +
                                    TypeDescription
                                    Type

                                    Type

                                    +
                                    + + | + Improve this Doc + + + View Source

                                    CreateType(IList<DynamicProperty>, Boolean)

                                    @@ -140,7 +196,7 @@

                                    Declaration
                                    -
                                    public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool createParameterCtor = true)
                                    +
                                    public static Type CreateType(IList<DynamicProperty> properties, bool createParameterCtor = true)
                                    Parameters
                                    @@ -153,13 +209,13 @@
                                    Parameters
                                    - + - + @@ -176,7 +232,7 @@
                                    Returns
                                    - + @@ -198,15 +254,16 @@
                                    diff --git a/docs/api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html b/docs/api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html index 6d94ef25..f1a51c81 100644 --- a/docs/api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html +++ b/docs/api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                    -
                                    +
                                    Search Results for

                                    -
                                      +
                                        IList<DynamicProperty>IList<DynamicProperty> properties

                                        The DynamicProperties

                                        BooleanBoolean createParameterCtor

                                        Create a constructor with parameters. Default set to true. Note that for Linq-to-Database objects, this needs to be set to false.

                                        TypeType

                                        Type

                                        @@ -150,9 +150,9 @@
                                        Parameters
                                        - + - @@ -167,7 +167,7 @@
                                        Returns
                                        - + @@ -175,19 +175,19 @@
                                        Returns
                                        IEnumerableIEnumerable source

                                        A IEnumerable to create an array from.

                                        +

                                        A IEnumerable to create an array from.

                                        Object[]Object[]

                                        An array that contains the elements from the input sequence.

                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                        ToDynamicArray(IEnumerable, Type)

                                        -

                                        Creates an array of dynamic objects from a IEnumerable.

                                        +

                                        Creates an array of dynamic objects from a IEnumerable.

                                        Declaration
                                        -
                                        public static object[] ToDynamicArray([NotNull] this IEnumerable source, [NotNull] Type type)
                                        +
                                        public static object[] ToDynamicArray(this IEnumerable source, Type type)
                                        Parameters
                                        @@ -200,15 +200,15 @@
                                        Parameters
                                        - + - - + - @@ -223,7 +223,7 @@
                                        Returns
                                        - + @@ -231,19 +231,19 @@
                                        Returns
                                        IEnumerableIEnumerable source

                                        A IEnumerable to create an array from.

                                        +

                                        A IEnumerable to create an array from.

                                        TypeType type

                                        A Type cast to.

                                        +

                                        A Type cast to.

                                        Object[]Object[]

                                        An Array that contains the elements from the input sequence.

                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                        ToDynamicArray<T>(IEnumerable)

                                        -

                                        Creates an array of dynamic objects from a IEnumerable.

                                        +

                                        Creates an array of dynamic objects from a IEnumerable.

                                        Declaration
                                        -
                                        public static T[] ToDynamicArray<T>([NotNull] this IEnumerable source)
                                        +
                                        public static T[] ToDynamicArray<T>(this IEnumerable source)
                                        Parameters
                                        @@ -256,9 +256,9 @@
                                        Parameters
                                        - + - @@ -297,19 +297,19 @@
                                        Type Parameters
                                        IEnumerableIEnumerable source

                                        A IEnumerable to create an array from.

                                        +

                                        A IEnumerable to create an array from.

                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                        ToDynamicList(IEnumerable)

                                        -

                                        Creates a list of dynamic objects from a IEnumerable.

                                        +

                                        Creates a list of dynamic objects from a IEnumerable.

                                        Declaration
                                        -
                                        public static List<object> ToDynamicList([NotNull] this IEnumerable source)
                                        +
                                        public static List<object> ToDynamicList(this IEnumerable source)
                                        Parameters
                                        @@ -322,9 +322,9 @@
                                        Parameters
                                        - + - @@ -339,7 +339,7 @@
                                        Returns
                                        - + @@ -347,19 +347,19 @@
                                        Returns
                                        IEnumerableIEnumerable source

                                        A IEnumerable to create an array from.

                                        +

                                        A IEnumerable to create an array from.

                                        List<Object>List<Object>

                                        A List that contains the elements from the input sequence.

                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                        ToDynamicList(IEnumerable, Type)

                                        -

                                        Creates a list of dynamic objects from a IEnumerable.

                                        +

                                        Creates a list of dynamic objects from a IEnumerable.

                                        Declaration
                                        -
                                        public static List<object> ToDynamicList([NotNull] this IEnumerable source, [NotNull] Type type)
                                        +
                                        public static List<object> ToDynamicList(this IEnumerable source, Type type)
                                        Parameters
                                        @@ -372,15 +372,15 @@
                                        Parameters
                                        - + - - + - @@ -395,7 +395,7 @@
                                        Returns
                                        - + @@ -403,19 +403,19 @@
                                        Returns
                                        IEnumerableIEnumerable source

                                        A IEnumerable to create an array from.

                                        +

                                        A IEnumerable to create an array from.

                                        TypeType type

                                        A Type cast to.

                                        +

                                        A Type cast to.

                                        List<Object>List<Object>

                                        A List that contains the elements from the input sequence.

                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                        ToDynamicList<T>(IEnumerable)

                                        -

                                        Creates a list of dynamic objects from a IEnumerable.

                                        +

                                        Creates a list of dynamic objects from a IEnumerable.

                                        Declaration
                                        -
                                        public static List<T> ToDynamicList<T>([NotNull] this IEnumerable source)
                                        +
                                        public static List<T> ToDynamicList<T>(this IEnumerable source)
                                        Parameters
                                        @@ -428,9 +428,9 @@
                                        Parameters
                                        - + - @@ -445,7 +445,7 @@
                                        Returns
                                        - + @@ -475,15 +475,16 @@
                                        Type Parameters
                                        diff --git a/docs/api/System.Linq.Dynamic.Core.DynamicExpressionParser.html b/docs/api/System.Linq.Dynamic.Core.DynamicExpressionParser.html index 3b576d8c..95ce693d 100644 --- a/docs/api/System.Linq.Dynamic.Core.DynamicExpressionParser.html +++ b/docs/api/System.Linq.Dynamic.Core.DynamicExpressionParser.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                        -
                                        +
                                        Search Results for

                                        -
                                          +
                                            Inheritance
                                            - +
                                            DynamicExpressionParser
                                            Namespace: System.Linq.Dynamic.Core
                                            @@ -125,10 +125,10 @@

                                            Methods

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(Boolean, ParameterExpression[], Type, String, Object[])

                                            @@ -138,7 +138,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            Parameters
                                            IEnumerableIEnumerable source

                                            A IEnumerable to create an array from.

                                            +

                                            A IEnumerable to create an array from.

                                            List<T>List<T>

                                            A List{T} that contains the elements from the input sequence.

                                            @@ -151,31 +151,31 @@
                                            Parameters
                                            - + - + - + - + - + @@ -192,18 +192,18 @@
                                            Returns
                                            - - +
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            ParameterExpression[]ParameterExpression[] parameters

                                            A array from ParameterExpressions.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(Boolean, Type, Type, String, Object[])

                                            @@ -213,7 +213,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -226,31 +226,31 @@
                                            Parameters
                                            - + - + - + - + - + @@ -267,18 +267,18 @@
                                            Returns
                                            - - +
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            TypeType itType

                                            The main type from the dynamic class expression.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParsingConfig, Boolean, ParameterExpression[], Type, String, Object[])

                                            @@ -288,7 +288,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -307,31 +307,31 @@
                                            Parameters
                                            - + - + - + - + - + @@ -348,18 +348,18 @@
                                            Returns
                                            - - +
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            ParameterExpression[]ParameterExpression[] parameters

                                            A array from ParameterExpressions.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParsingConfig, Boolean, Type, String, Object[])

                                            @@ -369,7 +369,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -388,25 +388,25 @@
                                            Parameters
                                            - + - + - + - + @@ -423,18 +423,18 @@
                                            Returns
                                            - - +
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParsingConfig, Boolean, Type, Type, String, Object[])

                                            @@ -444,7 +444,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, Type itType, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -463,31 +463,31 @@
                                            Parameters
                                            - + - + - + - + - + @@ -504,18 +504,18 @@
                                            Returns
                                            - - +
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            TypeType itType

                                            The main type from the dynamic class expression.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParsingConfig, ParameterExpression[], Type, String, Object[])

                                            @@ -525,7 +525,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -544,25 +544,25 @@
                                            Parameters
                                            - + - + - + - + @@ -579,18 +579,18 @@
                                            Returns
                                            - - +
                                            ParameterExpression[]ParameterExpression[] parameters

                                            A array from ParameterExpressions.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParsingConfig, Type, String, Object[])

                                            @@ -600,7 +600,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -619,19 +619,19 @@
                                            Parameters
                                            - + - + - + @@ -648,18 +648,18 @@
                                            Returns
                                            - - +
                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParsingConfig, Type, Type, String, Object[])

                                            @@ -669,7 +669,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, Type itType, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -688,25 +688,25 @@
                                            Parameters
                                            - + - + - + - + @@ -723,18 +723,18 @@
                                            Returns
                                            - - +
                                            TypeType itType

                                            The main type from the dynamic class expression.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(ParameterExpression[], Type, String, Object[])

                                            @@ -744,7 +744,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -757,25 +757,25 @@
                                            Parameters
                                            - + - + - + - + @@ -792,18 +792,585 @@
                                            Returns
                                            - - +
                                            ParameterExpression[]ParameterExpression[] parameters

                                            A array from ParameterExpressions.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source + + +

                                            ParseLambda(Type, ParsingConfig, Boolean, ParameterExpression[], Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression.

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            BooleancreateParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            +
                                            ParameterExpression[]parameters

                                            A array from ParameterExpressions.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda(Type, ParsingConfig, Boolean, Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression.

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            BooleancreateParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda(Type, ParsingConfig, Boolean, Type, Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression.

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, Type itType, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            BooleancreateParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            +
                                            TypeitType

                                            The main type from the dynamic class expression.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda(Type, ParsingConfig, ParameterExpression[], Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            ParameterExpression[]parameters

                                            A array from ParameterExpressions.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda(Type, ParsingConfig, Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda(Type, ParsingConfig, Type, Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, Type itType, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            TypeitType

                                            The main type from the dynamic class expression.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda(Type, ParameterExpression[], Type, String, Object[])

                                            +

                                            Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParameterExpression[]parameters

                                            A array from ParameterExpressions.

                                            +
                                            TyperesultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            + + | + Improve this Doc + + + View Source

                                            ParseLambda(Type, String, Object[])

                                            @@ -813,7 +1380,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -826,19 +1393,19 @@
                                            Parameters
                                            - + - + - + @@ -855,18 +1422,18 @@
                                            Returns
                                            - - +
                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda(Type, Type, String, Object[])

                                            @@ -876,7 +1443,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
                                            +public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)
                                            Parameters
                                            @@ -889,25 +1456,25 @@
                                            Parameters
                                            - + - + - + - + @@ -924,18 +1491,18 @@
                                            Returns
                                            - - +
                                            TypeType itType

                                            The main type from the dynamic class expression.

                                            TypeType resultType

                                            Type of the result. If not specified, it will be generated dynamically.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            LambdaExpression

                                            The generated LambdaExpression

                                            +
                                            LambdaExpression

                                            The generated LambdaExpression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda<TResult>(ParsingConfig, Boolean, ParameterExpression[], String, Object[])

                                            @@ -945,7 +1512,7 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static Expression<Func<TResult>> ParseLambda<TResult>([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [NotNull] string expression, params object[] values)
                                            +public static Expression<Func<TResult>> ParseLambda<TResult>(ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values)
                                            Parameters
                                            @@ -964,25 +1531,25 @@
                                            Parameters
                                            - + - + - + - + @@ -999,8 +1566,8 @@
                                            Returns
                                            - - + @@ -1023,10 +1590,10 @@
                                            Type Parameters
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            ParameterExpression[]ParameterExpression[] parameters

                                            A array from ParameterExpressions.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            Expression<Func<TResult>>

                                            The generated Expression

                                            +
                                            Expression<Func<TResult>>

                                            The generated Expression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda<TResult>(ParsingConfig, Boolean, String, Object[])

                                            @@ -1036,7 +1603,189 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static Expression<Func<TResult>> ParseLambda<TResult>([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values)
                                            +public static Expression<Func<TResult>> ParseLambda<TResult>(ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values) +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            BooleancreateParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            Expression<Func<TResult>>

                                            The generated Expression

                                            +
                                            +
                                            Type Parameters
                                            + + + + + + + + + + + + + +
                                            NameDescription
                                            TResult

                                            The type of the result.

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda<TResult>(Type, ParsingConfig, Boolean, ParameterExpression[], String, Object[])

                                            +

                                            Parses an expression into a Typed Expression.

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static Expression<Func<TResult>> ParseLambda<TResult>(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values)
                                            +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            BooleancreateParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            +
                                            ParameterExpression[]parameters

                                            A array from ParameterExpressions.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            Expression<Func<TResult>>

                                            The generated Expression

                                            +
                                            +
                                            Type Parameters
                                            + + + + + + + + + + + + + +
                                            NameDescription
                                            TResult

                                            The type of the result.

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda<TResult>(Type, ParsingConfig, Boolean, String, Object[])

                                            +

                                            Parses an expression into a Typed Expression.

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static Expression<Func<TResult>> ParseLambda<TResult>(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values)
                                            Parameters
                                            @@ -1048,6 +1797,12 @@
                                            Parameters
                                            + + + + + @@ -1055,19 +1810,19 @@
                                            Parameters
                                            - + - + - + @@ -1084,8 +1839,8 @@
                                            Returns
                                            - - + @@ -1108,10 +1863,10 @@
                                            Type Parameters
                                            TypedelegateType

                                            The delegate type.

                                            +
                                            ParsingConfig parsingConfig
                                            BooleanBoolean createParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            StringString expression

                                            The expression.

                                            Object[]Object[] values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            Expression<Func<TResult>>

                                            The generated Expression

                                            +
                                            Expression<Func<TResult>>

                                            The generated Expression

                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                            ParseLambda<T, TResult>(ParsingConfig, Boolean, String, Object[])

                                            @@ -1121,7 +1876,97 @@

                                            Declaration

                                            [PublicAPI]
                                            -public static Expression<Func<T, TResult>> ParseLambda<T, TResult>([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values)
                                            +public static Expression<Func<T, TResult>> ParseLambda<T, TResult>(ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values) +
                                            +
                                            Parameters
                                            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                            TypeNameDescription
                                            ParsingConfigparsingConfig

                                            The Configuration for the parsing.

                                            +
                                            BooleancreateParameterCtor

                                            if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                            +
                                            Stringexpression

                                            The expression.

                                            +
                                            Object[]values

                                            An object array that contains zero or more objects which are used as replacement values.

                                            +
                                            +
                                            Returns
                                            + + + + + + + + + + + + + +
                                            TypeDescription
                                            Expression<Func<T, TResult>>

                                            The generated Expression

                                            +
                                            +
                                            Type Parameters
                                            + + + + + + + + + + + + + + + + + +
                                            NameDescription
                                            T

                                            The it-Type.

                                            +
                                            TResult

                                            The type of the result.

                                            +
                                            + + | + Improve this Doc + + + View Source + + +

                                            ParseLambda<T, TResult>(Type, ParsingConfig, Boolean, String, Object[])

                                            +

                                            Parses an expression into a Typed Expression.

                                            +
                                            +
                                            +
                                            Declaration
                                            +
                                            +
                                            [PublicAPI]
                                            +public static Expression<Func<T, TResult>> ParseLambda<T, TResult>(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values)
                                            Parameters
                                            @@ -1133,6 +1978,12 @@
                                            Parameters
                                            + + + + + @@ -1140,19 +1991,19 @@
                                            Parameters
                                            - + - + - + @@ -1169,8 +2020,8 @@
                                            Returns
                                            - - + @@ -1204,15 +2055,16 @@
                                            Type Parameters
                                            diff --git a/docs/api/System.Linq.Dynamic.Core.DynamicProperty.html b/docs/api/System.Linq.Dynamic.Core.DynamicProperty.html index ddc6dbfd..aa122e67 100644 --- a/docs/api/System.Linq.Dynamic.Core.DynamicProperty.html +++ b/docs/api/System.Linq.Dynamic.Core.DynamicProperty.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                            -
                                            +
                                            Search Results for

                                            -
                                              +
                                                Inheritance
                                                - +
                                                DynamicProperty
                                                Namespace: System.Linq.Dynamic.Core
                                                @@ -125,10 +125,10 @@

                                                Constructors

                                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                                DynamicProperty(String, Type)

                                                @@ -150,13 +150,13 @@
                                                Parameters
                                                - + - + @@ -167,10 +167,10 @@

                                                Properties

                                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                                Name

                                                @@ -191,7 +191,7 @@
                                                Property Value
                                                - + @@ -199,10 +199,10 @@
                                                Property Value
                                                TypedelegateType

                                                The delegate type.

                                                +
                                                ParsingConfig parsingConfig
                                                BooleanBoolean createParameterCtor

                                                if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.

                                                StringString expression

                                                The expression.

                                                Object[]Object[] values

                                                An object array that contains zero or more objects which are used as replacement values.

                                                Expression<Func<T, TResult>>

                                                The generated Expression

                                                +
                                                Expression<Func<T, TResult>>

                                                The generated Expression

                                                StringString name

                                                The name from the property.

                                                TypeType type

                                                The type from the property.

                                                StringString

                                                The name from the property.

                                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                                Type

                                                @@ -223,7 +223,7 @@
                                                Property Value
                                                - Type + Type

                                                The type from the property.

                                                @@ -237,15 +237,16 @@
                                                Property Value
                                                diff --git a/docs/api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html b/docs/api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html index 7b7d92fc..f72aca2c 100644 --- a/docs/api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html +++ b/docs/api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                -
                                                +
                                                Search Results for

                                                -
                                                  +
                                                    Declaration
                                                    -
                                                    public static bool Any([NotNull] this IQueryable source)
                                                    +
                                                    public static bool Any(this IQueryable source)
                                                    Parameters
                                                    @@ -354,7 +346,7 @@
                                                    Parameters
                                                    - + @@ -371,7 +363,7 @@
                                                    Returns
                                                    - + @@ -383,10 +375,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Any(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -396,7 +388,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static bool Any([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +public static bool Any(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence to check for being empty.

                                                    BooleanBoolean

                                                    true if the source sequence contains any elements; otherwise, false.

                                                    @@ -409,7 +401,7 @@
                                                    Parameters
                                                    - + @@ -421,13 +413,13 @@
                                                    Parameters
                                                    - + - + @@ -444,7 +436,7 @@
                                                    Returns
                                                    - + @@ -458,10 +450,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Any(IQueryable, LambdaExpression)

                                                    @@ -470,7 +462,7 @@

                                                    Declaration
                                                    -
                                                    public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static bool Any(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence to check for being empty.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    BooleanBoolean

                                                    true if the source sequence contains any elements; otherwise, false.

                                                    @@ -483,13 +475,13 @@
                                                    Parameters
                                                    - + - + @@ -506,7 +498,7 @@
                                                    Returns
                                                    - + @@ -514,18 +506,19 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    A sequence to check for being empty.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    BooleanBoolean

                                                    true if the source sequence contains any elements; otherwise, false.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Any(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Determines whether a sequence contains any elements.

                                                    +
                                                    Declaration
                                                    -
                                                    public static bool Any([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static bool Any(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -538,17 +531,17 @@
                                                    Parameters
                                                    - + - + - + @@ -564,26 +557,27 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    BooleanBoolean

                                                    true if the source sequence contains any elements; otherwise, false.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    AsEnumerable(IQueryable)

                                                    -

                                                    Returns the input typed as IEnumerable<T> of Object./>

                                                    + +

                                                    AsDynamicEnumerable(IQueryable)

                                                    +

                                                    Returns the input typed as IEnumerable<T> of Object./>

                                                    Declaration
                                                    -
                                                    public static IEnumerable<object> AsEnumerable([NotNull] this IQueryable source)
                                                    +
                                                    public static IEnumerable<object> AsDynamicEnumerable(this IQueryable source)
                                                    Parameters
                                                    @@ -596,9 +590,9 @@
                                                    Parameters
                                                    - + - @@ -613,18 +607,18 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The sequence to type as IEnumerable<T> of Object.

                                                    +

                                                    The sequence to type as IEnumerable<T> of Object.

                                                    IEnumerable<Object>

                                                    The input typed as IEnumerable<T> of Object.

                                                    +
                                                    IEnumerable<Object>

                                                    The input typed as IEnumerable<T> of Object.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Average(IQueryable)

                                                    @@ -634,7 +628,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static double Average([NotNull] this IQueryable source)
                                                    +public static double Average(this IQueryable source)
                                                    Parameters
                                                    @@ -647,7 +641,7 @@
                                                    Parameters
                                                    - + @@ -664,7 +658,7 @@
                                                    Returns
                                                    - + @@ -677,10 +671,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Average(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -690,7 +684,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static double Average([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +public static double Average(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of numeric values to calculate the average of.

                                                    DoubleDouble

                                                    The average of the values in the sequence.

                                                    @@ -703,7 +697,7 @@
                                                    Parameters
                                                    - + @@ -715,13 +709,13 @@
                                                    Parameters
                                                    - + - + @@ -738,7 +732,7 @@
                                                    Returns
                                                    - + @@ -750,10 +744,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Average(IQueryable, LambdaExpression)

                                                    @@ -763,7 +757,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static double Average([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +public static double Average(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of numeric values to calculate the average of.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    DoubleDouble

                                                    The average of the values in the sequence.

                                                    @@ -776,13 +770,13 @@
                                                    Parameters
                                                    - + - + @@ -799,7 +793,7 @@
                                                    Returns
                                                    - + @@ -807,19 +801,20 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    A sequence of numeric values to calculate the average of.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A Lambda Expression.

                                                    DoubleDouble

                                                    The average of the values in the sequence.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Average(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Computes the average of a sequence of numeric values.

                                                    +
                                                    Declaration
                                                    [PublicAPI]
                                                    -public static double Average([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
                                                    +public static double Average(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -832,17 +827,17 @@
                                                    Parameters
                                                    - + - + - + @@ -858,26 +853,27 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    DoubleDouble

                                                    The average of the values in the sequence.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Cast(IQueryable, ParsingConfig, String)

                                                    -

                                                    Converts the elements of an IQueryable to the specified type.

                                                    +

                                                    Converts the elements of an IQueryable to the specified type.

                                                    Declaration
                                                    -
                                                    public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName)
                                                    +
                                                    public static IQueryable Cast(this IQueryable source, ParsingConfig config, string typeName)
                                                    Parameters
                                                    @@ -890,9 +886,9 @@
                                                    Parameters
                                                    - + - @@ -902,7 +898,7 @@
                                                    Parameters
                                                    - + @@ -919,27 +915,27 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be converted.

                                                    +

                                                    The IQueryable that contains the elements to be converted.

                                                    StringString typeName

                                                    The type to convert the elements of source to.

                                                    IQueryable

                                                    An IQueryable that contains each element of the source sequence converted to the specified type.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains each element of the source sequence converted to the specified type.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Cast(IQueryable, String)

                                                    -

                                                    Converts the elements of an IQueryable to the specified type.

                                                    +

                                                    Converts the elements of an IQueryable to the specified type.

                                                    Declaration
                                                    -
                                                    public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] string typeName)
                                                    +
                                                    public static IQueryable Cast(this IQueryable source, string typeName)
                                                    Parameters
                                                    @@ -952,13 +948,13 @@
                                                    Parameters
                                                    - + - - + @@ -975,27 +971,27 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be converted.

                                                    +

                                                    The IQueryable that contains the elements to be converted.

                                                    StringString typeName

                                                    The type to convert the elements of source to.

                                                    IQueryable

                                                    An IQueryable that contains each element of the source sequence converted to the specified type.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains each element of the source sequence converted to the specified type.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Cast(IQueryable, Type)

                                                    -

                                                    Converts the elements of an IQueryable to the specified type.

                                                    +

                                                    Converts the elements of an IQueryable to the specified type.

                                                    Declaration
                                                    -
                                                    public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Type type)
                                                    +
                                                    public static IQueryable Cast(this IQueryable source, Type type)
                                                    Parameters
                                                    @@ -1008,13 +1004,13 @@
                                                    Parameters
                                                    - + - - + @@ -1031,18 +1027,18 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be converted.

                                                    +

                                                    The IQueryable that contains the elements to be converted.

                                                    TypeType type

                                                    The type to convert the elements of source to.

                                                    IQueryable

                                                    An IQueryable that contains each element of the source sequence converted to the specified type.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains each element of the source sequence converted to the specified type.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Count(IQueryable)

                                                    @@ -1051,7 +1047,7 @@

                                                    Declaration
                                                    -
                                                    public static int Count([NotNull] this IQueryable source)
                                                    +
                                                    public static int Count(this IQueryable source)
                                                    Parameters
                                                    @@ -1064,9 +1060,9 @@
                                                    Parameters
                                                    - + - @@ -1081,7 +1077,7 @@
                                                    Returns
                                                    - + @@ -1093,10 +1089,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Count(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -1106,7 +1102,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static int Count([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +public static int Count(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be counted.

                                                    +

                                                    The IQueryable that contains the elements to be counted.

                                                    Int32Int32

                                                    The number of elements in the input sequence.

                                                    @@ -1119,9 +1115,9 @@
                                                    Parameters
                                                    - + - @@ -1131,13 +1127,13 @@
                                                    Parameters
                                                    - + - + @@ -1154,7 +1150,7 @@
                                                    Returns
                                                    - + @@ -1168,10 +1164,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Count(IQueryable, LambdaExpression)

                                                    @@ -1180,7 +1176,7 @@

                                                    Declaration
                                                    -
                                                    public static int Count([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static int Count(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be counted.

                                                    +

                                                    The IQueryable that contains the elements to be counted.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    Int32Int32

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    @@ -1193,13 +1189,13 @@
                                                    Parameters
                                                    - + - - + @@ -1216,7 +1212,7 @@
                                                    Returns
                                                    - + @@ -1224,18 +1220,19 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be counted.

                                                    +

                                                    The IQueryable that contains the elements to be counted.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    Int32Int32

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Count(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Returns the number of elements in a sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static int Count([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static int Count(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -1248,17 +1245,17 @@
                                                    Parameters
                                                    - + - + - + @@ -1274,17 +1271,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    Int32Int32

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    DefaultIfEmpty(IQueryable)

                                                    @@ -1293,7 +1291,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source)
                                                    +
                                                    public static IQueryable DefaultIfEmpty(this IQueryable source)
                                                    Parameters
                                                    @@ -1306,9 +1304,9 @@
                                                    Parameters
                                                    - + - @@ -1323,8 +1321,8 @@
                                                    Returns
                                                    - - + @@ -1334,10 +1332,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    DefaultIfEmpty(IQueryable, Object)

                                                    @@ -1346,7 +1344,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source, [CanBeNull] object defaultValue)
                                                    +
                                                    public static IQueryable DefaultIfEmpty(this IQueryable source, object defaultValue)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    The IQueryable to return a default value for if empty.

                                                    +

                                                    The IQueryable to return a default value for if empty.

                                                    IQueryable

                                                    An IQueryable that contains default if source is empty; otherwise, source.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains default if source is empty; otherwise, source.

                                                    @@ -1359,13 +1357,13 @@
                                                    Parameters
                                                    - + - - + @@ -1382,8 +1380,8 @@
                                                    Returns
                                                    - - + @@ -1393,10 +1391,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Distinct(IQueryable)

                                                    @@ -1405,7 +1403,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Distinct([NotNull] this IQueryable source)
                                                    +
                                                    public static IQueryable Distinct(this IQueryable source)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    The IQueryable to return a default value for if empty.

                                                    +

                                                    The IQueryable to return a default value for if empty.

                                                    ObjectObject defaultValue

                                                    The value to return if the sequence is empty.

                                                    IQueryable

                                                    An IQueryable that contains defaultValue if source is empty; otherwise, source.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains defaultValue if source is empty; otherwise, source.

                                                    @@ -1418,7 +1416,7 @@
                                                    Parameters
                                                    - + @@ -1435,8 +1433,8 @@
                                                    Returns
                                                    - - + @@ -1448,10 +1446,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    First(IQueryable)

                                                    @@ -1460,7 +1458,7 @@

                                                    Declaration
                                                    -
                                                    public static object First([NotNull] this IQueryable source)
                                                    +
                                                    public static object First(this IQueryable source)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    The sequence to remove duplicate elements from.

                                                    IQueryable

                                                    An IQueryable that contains distinct elements from the source sequence.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains distinct elements from the source sequence.

                                                    @@ -1473,9 +1471,9 @@
                                                    Parameters
                                                    - + - @@ -1490,7 +1488,7 @@
                                                    Returns
                                                    - + @@ -1498,10 +1496,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the first element of.

                                                    +

                                                    The IQueryable to return the first element of.

                                                    ObjectObject

                                                    The first element in source.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    First(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -1511,7 +1509,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static object First([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +public static object First(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -1524,9 +1522,9 @@
                                                    Parameters
                                                    - + - @@ -1536,13 +1534,13 @@
                                                    Parameters
                                                    - + - + @@ -1559,7 +1557,7 @@
                                                    Returns
                                                    - + @@ -1567,10 +1565,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the first element of.

                                                    +

                                                    The IQueryable to return the first element of.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    First(IQueryable, LambdaExpression)

                                                    @@ -1579,7 +1577,7 @@

                                                    Declaration
                                                    -
                                                    public static object First([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static object First(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -1592,13 +1590,13 @@
                                                    Parameters
                                                    - + - - + @@ -1615,7 +1613,7 @@
                                                    Returns
                                                    - + @@ -1623,18 +1621,19 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the first element of.

                                                    +

                                                    The IQueryable to return the first element of.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    First(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Returns the first element of a sequence that satisfies a specified condition.

                                                    +
                                                    Declaration
                                                    -
                                                    public static object First([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static object First(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -1647,17 +1646,17 @@
                                                    Parameters
                                                    - + - + - + @@ -1673,17 +1672,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    FirstOrDefault(IQueryable)

                                                    @@ -1692,7 +1692,7 @@

                                                    Declaration
                                                    -
                                                    public static object FirstOrDefault([NotNull] this IQueryable source)
                                                    +
                                                    public static object FirstOrDefault(this IQueryable source)
                                                    Parameters
                                                    @@ -1705,9 +1705,9 @@
                                                    Parameters
                                                    - + - @@ -1722,7 +1722,7 @@
                                                    Returns
                                                    - + @@ -1730,10 +1730,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the first element of.

                                                    +

                                                    The IQueryable to return the first element of.

                                                    ObjectObject

                                                    default if source is empty; otherwise, the first element in source.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    FirstOrDefault(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -1743,7 +1743,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +public static object FirstOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -1756,9 +1756,9 @@
                                                    Parameters
                                                    - + - @@ -1768,13 +1768,13 @@
                                                    Parameters
                                                    - + - + @@ -1791,7 +1791,7 @@
                                                    Returns
                                                    - + @@ -1799,10 +1799,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the first element of.

                                                    +

                                                    The IQueryable to return the first element of.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    ObjectObject

                                                    default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    FirstOrDefault(IQueryable, LambdaExpression)

                                                    @@ -1811,7 +1811,7 @@

                                                    Declaration
                                                    -
                                                    public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static object FirstOrDefault(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -1824,13 +1824,13 @@
                                                    Parameters
                                                    - + - - + @@ -1847,7 +1847,7 @@
                                                    Returns
                                                    - + @@ -1855,18 +1855,19 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the first element of.

                                                    +

                                                    The IQueryable to return the first element of.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    ObjectObject

                                                    default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    FirstOrDefault(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found.

                                                    +
                                                    Declaration
                                                    -
                                                    public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static object FirstOrDefault(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -1879,17 +1880,17 @@
                                                    Parameters
                                                    - + - + - + @@ -1905,28 +1906,28 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    ObjectObject

                                                    default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    GroupBy(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    GroupBy(IQueryable, ParsingConfig, String, IEqualityComparer, Object[])

                                                    Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key.

                                                    Declaration
                                                    -
                                                    [PublicAPI]
                                                    -public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [CanBeNull] params object[] args)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, IEqualityComparer equalityComparer, params object[] args)
                                                    Parameters
                                                    @@ -1939,9 +1940,9 @@
                                                    Parameters
                                                    - + - @@ -1951,13 +1952,19 @@
                                                    Parameters
                                                    - + - + + + + + + @@ -1974,32 +1981,29 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    A IQueryable whose elements to group.

                                                    +

                                                    A IQueryable whose elements to group.

                                                    StringString keySelector

                                                    A string expression to specify the key for each element.

                                                    Object[]IEqualityComparerequalityComparer

                                                    The comparer to use.

                                                    +
                                                    Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    -
                                                    Examples
                                                    -
                                                    var groupResult1 = queryable.GroupBy("NumberPropertyAsKey");
                                                    -var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)");
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    GroupBy(IQueryable, ParsingConfig, String, String)

                                                    +

                                                    GroupBy(IQueryable, ParsingConfig, String, Object[])

                                                    Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key.

                                                    Declaration
                                                    -
                                                    public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector)
                                                    +
                                                    [PublicAPI]
                                                    +public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, params object[] args)
                                                    Parameters
                                                    @@ -2012,9 +2016,9 @@
                                                    Parameters
                                                    - + - @@ -2024,15 +2028,15 @@
                                                    Parameters
                                                    - + - - - + + @@ -2047,33 +2051,32 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    A IQueryable whose elements to group.

                                                    +

                                                    A IQueryable whose elements to group.

                                                    StringString keySelector

                                                    A string expression to specify the key for each element.

                                                    StringresultSelector

                                                    A string expression to specify a result value from each group.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    -
                                                    Examples
                                                    -
                                                    var groupResult1 = queryable.GroupBy("NumberPropertyAsKey", "StringProperty");
                                                    -var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)", "new (StringProperty1, StringProperty2)");
                                                    +
                                                    Examples
                                                    +
                                                    var groupResult1 = queryable.GroupBy("NumberPropertyAsKey");
                                                    +var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)");
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    GroupBy(IQueryable, ParsingConfig, String, String, Object[])

                                                    +

                                                    GroupBy(IQueryable, ParsingConfig, String, String)

                                                    Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key.

                                                    Declaration
                                                    -
                                                    [PublicAPI]
                                                    -public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector)
                                                    Parameters
                                                    @@ -2086,9 +2089,9 @@
                                                    Parameters
                                                    - + - @@ -2098,21 +2101,15 @@
                                                    Parameters
                                                    - + - + - - - - - @@ -2127,31 +2124,32 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    A IQueryable whose elements to group.

                                                    +

                                                    A IQueryable whose elements to group.

                                                    StringString keySelector

                                                    A string expression to specify the key for each element.

                                                    StringString resultSelector

                                                    A string expression to specify a result value from each group.

                                                    -
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    -
                                                    Examples
                                                    +
                                                    Examples
                                                    var groupResult1 = queryable.GroupBy("NumberPropertyAsKey", "StringProperty");
                                                     var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)", "new (StringProperty1, StringProperty2)");
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    GroupBy(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    GroupBy(IQueryable, ParsingConfig, String, String, IEqualityComparer)

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    Declaration
                                                    -
                                                    [PublicAPI]
                                                    -public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [CanBeNull] params object[] args)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer equalityComparer)
                                                    Parameters
                                                    @@ -2164,19 +2162,34 @@
                                                    Parameters
                                                    - + - + + + + + + - + - + - - - + + + + + + + +
                                                    IQueryableIQueryable source

                                                    A IQueryable whose elements to group.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    StringString keySelector

                                                    A string expression to specify the key for each element.

                                                    +
                                                    Object[]argsStringresultSelector

                                                    A string expression to specify a result value from each group.

                                                    +
                                                    IEqualityComparerequalityComparer

                                                    The comparer to use.

                                                    +
                                                    @@ -2190,25 +2203,28 @@
                                                    Returns
                                                    - IQueryable - + IQueryable +

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    GroupBy(IQueryable, String, String)

                                                    -
                                                    +

                                                    GroupBy(IQueryable, ParsingConfig, String, String, IEqualityComparer, Object[])

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer equalityComparer, object[] args)
                                                    Parameters
                                                    @@ -2221,19 +2237,40 @@
                                                    Parameters
                                                    - + - + + + + + + - + - + - + - + + + + + + + + + + +
                                                    IQueryableIQueryable source

                                                    A IQueryable whose elements to group.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    StringString keySelector

                                                    A string expression to specify the key for each element.

                                                    +
                                                    StringString resultSelector

                                                    A string expression to specify a result value from each group.

                                                    +
                                                    IEqualityComparerequalityComparer

                                                    The comparer to use.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    @@ -2247,26 +2284,29 @@
                                                    Returns
                                                    - IQueryable - + IQueryable +

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    GroupBy(IQueryable, String, String, Object[])

                                                    -
                                                    +

                                                    GroupBy(IQueryable, ParsingConfig, String, String, Object[])

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    Declaration
                                                    [PublicAPI]
                                                    -public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args)
                                                    +public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, object[] args)
                                                    Parameters
                                                    @@ -2279,24 +2319,34 @@
                                                    Parameters
                                                    - + - + + + + + + - + - + - + - + - + - +
                                                    IQueryableIQueryable source

                                                    A IQueryable whose elements to group.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    StringString keySelector

                                                    A string expression to specify the key for each element.

                                                    +
                                                    StringString resultSelector

                                                    A string expression to specify a result value from each group.

                                                    +
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    @@ -2310,27 +2360,32 @@
                                                    Returns
                                                    - IQueryable - + IQueryable +

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    + +
                                                    Examples
                                                    +
                                                    var groupResult1 = queryable.GroupBy("NumberPropertyAsKey", "StringProperty");
                                                    +var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)", "new (StringProperty1, StringProperty2)");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    GroupByMany<TElement>(IEnumerable<TElement>, Func<TElement, Object>[])

                                                    -

                                                    Groups the elements of a sequence according to multiple specified key functions -and creates a result value from each group (and subgroups) and its key.

                                                    + +

                                                    GroupBy(IQueryable, String, IEqualityComparer, Object[])

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    Declaration
                                                    -
                                                    public static IEnumerable<GroupResult> GroupByMany<TElement>([NotNull] this IEnumerable<TElement> source, params Func<TElement, object>[] keySelectors)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, string keySelector, IEqualityComparer equalityComparer, params object[] args)
                                                    Parameters
                                                    @@ -2343,66 +2398,60 @@
                                                    Parameters
                                                    - + - + - - - + + + - -
                                                    IEnumerable<TElement>IQueryable source

                                                    A IEnumerable<T> whose elements to group.

                                                    -
                                                    Func<TElement, Object>[]keySelectors

                                                    Lambda expressions to specify the keys for each element.

                                                    -
                                                    StringkeySelector
                                                    -
                                                    Returns
                                                    - - - - + + + - - - - + + +
                                                    TypeDescriptionIEqualityComparerequalityComparer
                                                    IEnumerable<GroupResult>

                                                    A IEnumerable<T> of type GroupResult where each element represents a projection over a group, its key, and its subgroups.

                                                    -
                                                    Object[]args
                                                    -
                                                    Type Parameters
                                                    +
                                                    Returns
                                                    - + - - + +
                                                    NameType Description
                                                    TElementIQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    GroupByMany<TElement>(IEnumerable<TElement>, ParsingConfig, String[])

                                                    -

                                                    Groups the elements of a sequence according to multiple specified key string functions -and creates a result value from each group (and subgroups) and its key.

                                                    + +

                                                    GroupBy(IQueryable, String, Object[])

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    Declaration
                                                    -
                                                    public static IEnumerable<GroupResult> GroupByMany<TElement>([NotNull] this IEnumerable<TElement> source, [NotNull] ParsingConfig config, params string[] keySelectors)
                                                    +
                                                    [PublicAPI]
                                                    +public static IQueryable GroupBy(this IQueryable source, string keySelector, params object[] args)
                                                    Parameters
                                                    @@ -2415,22 +2464,19 @@
                                                    Parameters
                                                    - + - + - - - + + + - - - + + +
                                                    IEnumerable<TElement>IQueryable source

                                                    A IEnumerable<T> whose elements to group.

                                                    -
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    -
                                                    StringkeySelector
                                                    String[]keySelectors

                                                    String expressions to specify the keys for each element.

                                                    -
                                                    Object[]args
                                                    @@ -2444,41 +2490,28 @@
                                                    Returns
                                                    - IEnumerable<GroupResult> -

                                                    A IEnumerable<T> of type GroupResult where each element represents a projection over a group, its key, and its subgroups.

                                                    + IQueryable +

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    -
                                                    Type Parameters
                                                    - - - - - - - - - - - - - -
                                                    NameDescription
                                                    TElement
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    GroupByMany<TElement>(IEnumerable<TElement>, String[])

                                                    -
                                                    + +

                                                    GroupBy(IQueryable, String, String)

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IEnumerable<GroupResult> GroupByMany<TElement>([NotNull] this IEnumerable<TElement> source, params string[] keySelectors)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector)
                                                    Parameters
                                                    @@ -2491,61 +2524,54 @@
                                                    Parameters
                                                    - + - - + + - -
                                                    IEnumerable<TElement>IQueryable source
                                                    String[]keySelectorsStringkeySelector
                                                    -
                                                    Returns
                                                    - - - - - - - - - + +
                                                    TypeDescription
                                                    IEnumerable<GroupResult>StringresultSelector
                                                    -
                                                    Type Parameters
                                                    +
                                                    Returns
                                                    - + - - + +
                                                    NameType Description
                                                    TElementIQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    GroupJoin(IQueryable, IEnumerable, String, String, String, Object[])

                                                    -
                                                    + +

                                                    GroupBy(IQueryable, String, String, IEqualityComparer)

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args)
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer)
                                                    Parameters
                                                    @@ -2558,32 +2584,1129 @@
                                                    Parameters
                                                    - - + + - - + + - - + + - - + + - - - + +
                                                    IQueryableouterIQueryablesource
                                                    IEnumerableinnerStringkeySelector
                                                    StringouterKeySelectorStringresultSelector
                                                    StringinnerKeySelectorIEqualityComparerequalityComparer
                                                    StringresultSelector
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupBy(IQueryable, String, String, IEqualityComparer, Object[])

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer, object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource
                                                    StringkeySelector
                                                    StringresultSelector
                                                    IEqualityComparerequalityComparer
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupBy(IQueryable, String, String, Object[])

                                                    +

                                                    Groups the elements of a sequence according to a specified key string function +and creates a result value from each group and its key.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    [PublicAPI]
                                                    +public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource
                                                    StringkeySelector
                                                    StringresultSelector
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    A IQueryable where each element represents a projection over a group and its key.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupByMany<TElement>(IEnumerable<TElement>, Func<TElement, Object>[])

                                                    +

                                                    Groups the elements of a sequence according to multiple specified key functions +and creates a result value from each group (and subgroups) and its key.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IEnumerable<GroupResult> GroupByMany<TElement>(this IEnumerable<TElement> source, params Func<TElement, object>[] keySelectors)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IEnumerable<TElement>source

                                                    A IEnumerable<T> whose elements to group.

                                                    +
                                                    Func<TElement, Object>[]keySelectors

                                                    Lambda expressions to specify the keys for each element.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IEnumerable<GroupResult>

                                                    A IEnumerable<T> of type GroupResult where each element represents a projection over a group, its key, and its subgroups.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + + + + +
                                                    NameDescription
                                                    TElement
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupByMany<TElement>(IEnumerable<TElement>, ParsingConfig, String[])

                                                    +

                                                    Groups the elements of a sequence according to multiple specified key string functions +and creates a result value from each group (and subgroups) and its key.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IEnumerable<GroupResult> GroupByMany<TElement>(this IEnumerable<TElement> source, ParsingConfig config, params string[] keySelectors)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IEnumerable<TElement>source

                                                    A IEnumerable<T> whose elements to group.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    String[]keySelectors

                                                    String expressions to specify the keys for each element.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IEnumerable<GroupResult>

                                                    A IEnumerable<T> of type GroupResult where each element represents a projection over a group, its key, and its subgroups.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + + + + +
                                                    NameDescription
                                                    TElement
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupByMany<TElement>(IEnumerable<TElement>, String[])

                                                    +

                                                    Groups the elements of a sequence according to multiple specified key string functions +and creates a result value from each group (and subgroups) and its key.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IEnumerable<GroupResult> GroupByMany<TElement>(this IEnumerable<TElement> source, params string[] keySelectors)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IEnumerable<TElement>source
                                                    String[]keySelectors
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IEnumerable<GroupResult>

                                                    A IEnumerable<T> of type GroupResult where each element represents a projection over a group, its key, and its subgroups.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + + + + +
                                                    NameDescription
                                                    TElement
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupJoin(IQueryable, IEnumerable, String, String, String, Object[])

                                                    +

                                                    Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryableouter
                                                    IEnumerableinner
                                                    StringouterKeySelector
                                                    StringinnerKeySelector
                                                    StringresultSelector
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    An IQueryable obtained by performing a grouped join on two sequences.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    GroupJoin(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[])

                                                    +

                                                    Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable GroupJoin(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryableouter

                                                    The first sequence to join.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    IEnumerableinner

                                                    The sequence to join to the first sequence.

                                                    +
                                                    StringouterKeySelector

                                                    A dynamic function to extract the join key from each element of the first sequence.

                                                    +
                                                    StringinnerKeySelector

                                                    A dynamic function to extract the join key from each element of the second sequence.

                                                    +
                                                    StringresultSelector

                                                    A dynamic function to create a result element from an element from the first sequence and a collection of matching elements from the second sequence.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    An IQueryable obtained by performing a grouped join on two sequences.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Join(IQueryable, IEnumerable, String, String, String, Object[])

                                                    +

                                                    Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryableouter
                                                    IEnumerableinner
                                                    StringouterKeySelector
                                                    StringinnerKeySelector
                                                    StringresultSelector
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    An IQueryable obtained by performing an inner join on two sequences.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Join(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[])

                                                    +

                                                    Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryableouter

                                                    The first sequence to join.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    IEnumerableinner

                                                    The sequence to join to the first sequence.

                                                    +
                                                    StringouterKeySelector

                                                    A dynamic function to extract the join key from each element of the first sequence.

                                                    +
                                                    StringinnerKeySelector

                                                    A dynamic function to extract the join key from each element of the second sequence.

                                                    +
                                                    StringresultSelector

                                                    A dynamic function to create a result element from two matching elements.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    An IQueryable obtained by performing an inner join on two sequences.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Join<TElement>(IQueryable<TElement>, IEnumerable<TElement>, String, String, String, Object[])

                                                    +

                                                    Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable<TElement> Join<TElement>(this IQueryable<TElement> outer, IEnumerable<TElement> inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryable<TElement>outer
                                                    IEnumerable<TElement>inner
                                                    StringouterKeySelector
                                                    StringinnerKeySelector
                                                    StringresultSelector
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable<TElement>

                                                    An IQueryable<T> that has elements of type TResult obtained by performing an inner join on two sequences.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + + + + +
                                                    NameDescription
                                                    TElement

                                                    The type of the elements of both sequences, and the result.

                                                    +
                                                    +
                                                    Remarks
                                                    +

                                                    This overload only works on elements where both sequences and the resulting element match.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Join<TElement>(IQueryable<TElement>, ParsingConfig, IEnumerable<TElement>, String, String, String, Object[])

                                                    +

                                                    Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable<TElement> Join<TElement>(this IQueryable<TElement> outer, ParsingConfig config, IEnumerable<TElement> inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryable<TElement>outer

                                                    The first sequence to join.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    IEnumerable<TElement>inner

                                                    The sequence to join to the first sequence.

                                                    +
                                                    StringouterKeySelector

                                                    A dynamic function to extract the join key from each element of the first sequence.

                                                    +
                                                    StringinnerKeySelector

                                                    A dynamic function to extract the join key from each element of the second sequence.

                                                    +
                                                    StringresultSelector

                                                    A dynamic function to create a result element from two matching elements.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable<TElement>

                                                    An IQueryable<T> that has elements of type TResult obtained by performing an inner join on two sequences.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + + + + +
                                                    NameDescription
                                                    TElement

                                                    The type of the elements of both sequences, and the result.

                                                    +
                                                    +
                                                    Remarks
                                                    +

                                                    This overload only works on elements where both sequences and the resulting element match.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Last(IQueryable)

                                                    +

                                                    Returns the last element of a sequence.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object Last(this IQueryable source)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    The IQueryable to return the last element of.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    Object

                                                    The last element in source.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Last(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Returns the last element of a sequence that satisfies a specified condition.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object Last(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    The IQueryable to return the last element of.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringpredicate

                                                    A function to test each element for a condition.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Last(IQueryable, LambdaExpression)

                                                    +

                                                    Returns the last element of a sequence that satisfies a specified condition.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object Last(this IQueryable source, LambdaExpression lambda)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    The IQueryable to return the last element of.

                                                    +
                                                    LambdaExpressionlambda

                                                    A cached Lambda Expression.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Last(IQueryable, String, Object[])

                                                    +

                                                    Returns the last element of a sequence that satisfies a specified condition.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object Last(this IQueryable source, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + - + @@ -2599,26 +3722,27 @@
                                                    Returns
                                                    - - + +
                                                    TypeNameDescription
                                                    IQueryablesource
                                                    Stringpredicate
                                                    Object[]Object[] args
                                                    IQueryableObject

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    GroupJoin(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[])

                                                    -

                                                    Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys.

                                                    + +

                                                    LastOrDefault(IQueryable)

                                                    +

                                                    Returns the last element of a sequence, or a default value if the sequence contains no elements.

                                                    Declaration
                                                    -
                                                    public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args)
                                                    +
                                                    public static object LastOrDefault(this IQueryable source)
                                                    Parameters
                                                    @@ -2631,9 +3755,59 @@
                                                    Parameters
                                                    - - - + + + + +
                                                    IQueryableouter

                                                    The first sequence to join.

                                                    +
                                                    IQueryablesource

                                                    The IQueryable to return the last element of.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    Object

                                                    default if source is empty; otherwise, the last element in source.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    LastOrDefault(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object LastOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + @@ -2643,34 +3817,131 @@
                                                    Parameters
                                                    - - - + + - - - + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    The IQueryable to return the last element of.

                                                    IEnumerableinner

                                                    The sequence to join to the first sequence.

                                                    +
                                                    Stringpredicate

                                                    A function to test each element for a condition.

                                                    StringouterKeySelector

                                                    A dynamic function to extract the join key from each element of the first sequence.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    Returns
                                                    + + + + + + + + - - - + + + +
                                                    TypeDescription
                                                    StringinnerKeySelector

                                                    A dynamic function to extract the join key from each element of the second sequence.

                                                    +
                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    LastOrDefault(IQueryable, LambdaExpression)

                                                    +

                                                    Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object LastOrDefault(this IQueryable source, LambdaExpression lambda)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + - - - + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    The IQueryable to return the last element of.

                                                    StringresultSelector

                                                    A dynamic function to create a result element from an element from the first sequence and a collection of matching elements from the second sequence.

                                                    +
                                                    LambdaExpressionlambda

                                                    A cached Lambda Expression.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + +
                                                    TypeDescription
                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    + + | + Improve this Doc + + + View Source + + +

                                                    LastOrDefault(IQueryable, String, Object[])

                                                    +

                                                    Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static object LastOrDefault(this IQueryable source, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + - + - +
                                                    TypeNameDescription
                                                    IQueryablesource
                                                    Stringpredicate
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings.

                                                    -
                                                    @@ -2684,26 +3955,27 @@
                                                    Returns
                                                    - IQueryable -

                                                    An IQueryable obtained by performing a grouped join on two sequences.

                                                    + Object +

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Join(IQueryable, IEnumerable, String, String, String, Object[])

                                                    -
                                                    + +

                                                    LongCount(IQueryable)

                                                    +

                                                    Returns the number of elements in a sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args)
                                                    +
                                                    public static long LongCount(this IQueryable source)
                                                    Parameters
                                                    @@ -2716,34 +3988,10 @@
                                                    Parameters
                                                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
                                                    IQueryableouter
                                                    IEnumerableinner
                                                    StringouterKeySelector
                                                    StringinnerKeySelector
                                                    StringresultSelector
                                                    Object[]argsIQueryablesource

                                                    The IQueryable that contains the elements to be counted.

                                                    +
                                                    @@ -2757,26 +4005,32 @@
                                                    Returns
                                                    - IQueryable - + Int64 +

                                                    The number of elements in the input sequence.

                                                    + +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result = queryable.LongCount();
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Join(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[])

                                                    -

                                                    Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.

                                                    + +

                                                    LongCount(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Returns the number of elements in a sequence.

                                                    Declaration
                                                    -
                                                    public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args)
                                                    +
                                                    [PublicAPI]
                                                    +public static long LongCount(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -2789,9 +4043,9 @@
                                                    Parameters
                                                    - - - + + @@ -2801,33 +4055,15 @@
                                                    Parameters
                                                    - - - - - - - - - - - - - - - - - - + + - + - @@ -2842,26 +4078,33 @@
                                                    Returns
                                                    - - +
                                                    IQueryableouter

                                                    The first sequence to join.

                                                    +
                                                    IQueryablesource

                                                    The IQueryable that contains the elements to be counted.

                                                    IEnumerableinner

                                                    The sequence to join to the first sequence.

                                                    -
                                                    StringouterKeySelector

                                                    A dynamic function to extract the join key from each element of the first sequence.

                                                    -
                                                    StringinnerKeySelector

                                                    A dynamic function to extract the join key from each element of the second sequence.

                                                    -
                                                    StringresultSelector

                                                    A dynamic function to create a result element from two matching elements.

                                                    +
                                                    Stringpredicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings.

                                                    +

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable obtained by performing an inner join on two sequences.

                                                    +
                                                    Int64

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result1 = queryable.LongCount("Income > 50");
                                                    +var result2 = queryable.LongCount("Income > @0", 50);
                                                    +var result3 = queryable.Select("Roles.LongCount()");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Join<TElement>(IQueryable<TElement>, IEnumerable<TElement>, String, String, String, Object[])

                                                    -
                                                    + +

                                                    LongCount(IQueryable, LambdaExpression)

                                                    +

                                                    Returns the number of elements in a sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable<TElement> Join<TElement>([NotNull] this IQueryable<TElement> outer, [NotNull] IEnumerable<TElement> inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    public static long LongCount(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -2874,34 +4117,16 @@
                                                    Parameters
                                                    - - - - - - - - - - - - - - - - - - - - - - - + + + - - - + + +
                                                    IQueryable<TElement>outer
                                                    IEnumerable<TElement>inner
                                                    StringouterKeySelector
                                                    StringinnerKeySelector
                                                    StringresultSelectorIQueryablesource

                                                    The IQueryable that contains the elements to be counted.

                                                    +
                                                    Object[]argsLambdaExpressionlambda

                                                    A cached Lambda Expression.

                                                    +
                                                    @@ -2915,41 +4140,27 @@
                                                    Returns
                                                    - IQueryable<TElement> - - - - -
                                                    Type Parameters
                                                    - - - - - - - - - - - + +
                                                    NameDescription
                                                    TElementInt64

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Join<TElement>(IQueryable<TElement>, ParsingConfig, IEnumerable<TElement>, String, String, String, Object[])

                                                    -

                                                    Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys.

                                                    + +

                                                    LongCount(IQueryable, String, Object[])

                                                    +

                                                    Returns the number of elements in a sequence.

                                                    Declaration
                                                    -
                                                    public static IQueryable<TElement> Join<TElement>([NotNull] this IQueryable<TElement> outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable<TElement> inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args)
                                                    +
                                                    public static long LongCount(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -2962,46 +4173,19 @@
                                                    Parameters
                                                    - - - - - - - - - - - - - - - - - - - - - - - + + + - - - + + + - + - +
                                                    IQueryable<TElement>outer

                                                    The first sequence to join.

                                                    -
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    -
                                                    IEnumerable<TElement>inner

                                                    The sequence to join to the first sequence.

                                                    -
                                                    StringouterKeySelector

                                                    A dynamic function to extract the join key from each element of the first sequence.

                                                    -
                                                    StringinnerKeySelector

                                                    A dynamic function to extract the join key from each element of the second sequence.

                                                    -
                                                    IQueryablesource
                                                    StringresultSelector

                                                    A dynamic function to create a result element from two matching elements.

                                                    -
                                                    Stringpredicate
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings.

                                                    -
                                                    @@ -3015,46 +4199,28 @@
                                                    Returns
                                                    - IQueryable<TElement> -

                                                    An IQueryable<T> that has elements of type TResult obtained by performing an inner join on two sequences.

                                                    - - - - -
                                                    Type Parameters
                                                    - - - - - - - - - - - +
                                                    NameDescription
                                                    TElement

                                                    The type of the elements of both sequences, and the result.

                                                    +
                                                    Int64

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    -
                                                    Remarks
                                                    -

                                                    This overload only works on elements where both sequences and the resulting element match.

                                                    -
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Last(IQueryable)

                                                    -

                                                    Returns the last element of a sequence.

                                                    + +

                                                    Max(IQueryable)

                                                    +

                                                    Computes the max element of a sequence.

                                                    Declaration
                                                    -
                                                    public static object Last([NotNull] this IQueryable source)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Max(this IQueryable source)
                                                    Parameters
                                                    @@ -3067,9 +4233,9 @@
                                                    Parameters
                                                    - + - @@ -3084,27 +4250,33 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    A sequence of values to calculate find the max for.

                                                    Object

                                                    The last element in source.

                                                    +
                                                    Object

                                                    The max element in the sequence.

                                                    +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result1 = queryable.Max();
                                                    +var result2 = queryable.Select("Roles.Max()");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Last(IQueryable, ParsingConfig, String, Object[])

                                                    -

                                                    Returns the last element of a sequence that satisfies a specified condition.

                                                    + +

                                                    Max(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Computes the max element of a sequence.

                                                    Declaration
                                                    -
                                                    public static object Last([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Max(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -3117,9 +4289,9 @@
                                                    Parameters
                                                    - + - @@ -3129,13 +4301,13 @@
                                                    Parameters
                                                    - + - + @@ -3152,27 +4324,32 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    A sequence of values to calculate find the max for.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    Object

                                                    The max element in the sequence.

                                                    +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result = queryable.Max("Income");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Last(IQueryable, LambdaExpression)

                                                    -

                                                    Returns the last element of a sequence that satisfies a specified condition.

                                                    + +

                                                    Max(IQueryable, LambdaExpression)

                                                    +

                                                    Computes the max element of a sequence.

                                                    Declaration
                                                    -
                                                    public static object Last([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Max(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -3185,15 +4362,15 @@
                                                    Parameters
                                                    - + - - + - @@ -3208,26 +4385,28 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    A sequence of values to calculate find the max for.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    +

                                                    A Lambda Expression.

                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    Object

                                                    The max element in the sequence.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Last(IQueryable, String, Object[])

                                                    -
                                                    + +

                                                    Max(IQueryable, String, Object[])

                                                    +

                                                    Computes the max element of a sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static object Last([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Max(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -3240,17 +4419,17 @@
                                                    Parameters
                                                    - + - + - + @@ -3266,26 +4445,28 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    ObjectObject

                                                    The max element in the sequence.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LastOrDefault(IQueryable)

                                                    -

                                                    Returns the last element of a sequence, or a default value if the sequence contains no elements.

                                                    + +

                                                    Min(IQueryable)

                                                    +

                                                    Computes the min element of a sequence.

                                                    Declaration
                                                    -
                                                    public static object LastOrDefault([NotNull] this IQueryable source)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Min(this IQueryable source)
                                                    Parameters
                                                    @@ -3298,9 +4479,9 @@
                                                    Parameters
                                                    - + - @@ -3315,27 +4496,33 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    A sequence of values to calculate find the min for.

                                                    Object

                                                    default if source is empty; otherwise, the last element in source.

                                                    +
                                                    Object

                                                    The min element in the sequence.

                                                    +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result1 = queryable.Min();
                                                    +var result2 = queryable.Select("Roles.Min()");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LastOrDefault(IQueryable, ParsingConfig, String, Object[])

                                                    -

                                                    Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements.

                                                    + +

                                                    Min(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Computes the min element of a sequence.

                                                    Declaration
                                                    -
                                                    public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Min(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -3348,9 +4535,9 @@
                                                    Parameters
                                                    - + - @@ -3360,13 +4547,13 @@
                                                    Parameters
                                                    - + - + @@ -3383,27 +4570,32 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    A sequence of values to calculate find the min for.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    Object

                                                    The min element in the sequence.

                                                    +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result = queryable.Min("Income");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LastOrDefault(IQueryable, LambdaExpression)

                                                    -

                                                    Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements.

                                                    + +

                                                    Min(IQueryable, LambdaExpression)

                                                    +

                                                    Computes the min element of a sequence.

                                                    Declaration
                                                    -
                                                    public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Min(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -3416,15 +4608,15 @@
                                                    Parameters
                                                    - + - - + - @@ -3439,26 +4631,28 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    A sequence of values to calculate find the min for.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    +

                                                    A Lambda Expression.

                                                    Object

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    Object

                                                    The min element in the sequence.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LastOrDefault(IQueryable, String, Object[])

                                                    -
                                                    + +

                                                    Min(IQueryable, String, Object[])

                                                    +

                                                    Computes the min element of a sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    [PublicAPI]
                                                    +public static object Min(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -3471,17 +4665,17 @@
                                                    Parameters
                                                    - + - + - + @@ -3497,26 +4691,27 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    ObjectObject

                                                    The min element in the sequence.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LongCount(IQueryable)

                                                    -

                                                    Returns the number of elements in a sequence.

                                                    + +

                                                    OfType(IQueryable, ParsingConfig, String)

                                                    +

                                                    Filters the elements of an IQueryable based on a specified type.

                                                    Declaration
                                                    -
                                                    public static long LongCount([NotNull] this IQueryable source)
                                                    +
                                                    public static IQueryable OfType(this IQueryable source, ParsingConfig config, string typeName)
                                                    Parameters
                                                    @@ -3526,12 +4721,24 @@
                                                    Parameters
                                                    - - + + + + + + + + + + + + - - - + + @@ -3546,32 +4753,27 @@
                                                    Returns
                                                    - - +
                                                    Name Description
                                                    IQueryablesource

                                                    An IQueryable whose elements to filter.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    IQueryablesource

                                                    The IQueryable that contains the elements to be counted.

                                                    +
                                                    StringtypeName

                                                    The type to filter the elements of the sequence on.

                                                    Int64

                                                    The number of elements in the input sequence.

                                                    +
                                                    IQueryable

                                                    A collection that contains the elements from source that have the type.

                                                    -
                                                    Examples
                                                    -
                                                    IQueryable queryable = employees.AsQueryable();
                                                    -var result = queryable.LongCount();
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LongCount(IQueryable, ParsingConfig, String, Object[])

                                                    -

                                                    Returns the number of elements in a sequence.

                                                    + +

                                                    OfType(IQueryable, String)

                                                    +

                                                    Filters the elements of an IQueryable based on a specified type.

                                                    Declaration
                                                    -
                                                    [PublicAPI]
                                                    -public static long LongCount([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static IQueryable OfType(this IQueryable source, string typeName)
                                                    Parameters
                                                    @@ -3584,27 +4786,15 @@
                                                    Parameters
                                                    - + - - - - - - - - - - - - - - + + @@ -3619,33 +4809,27 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be counted.

                                                    -
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    -
                                                    Stringpredicate

                                                    A function to test each element for a condition.

                                                    +

                                                    An IQueryable whose elements to filter.

                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    StringtypeName

                                                    The type to filter the elements of the sequence on.

                                                    Int64

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    +
                                                    IQueryable

                                                    A collection that contains the elements from source that have the type.

                                                    -
                                                    Examples
                                                    -
                                                    IQueryable queryable = employees.AsQueryable();
                                                    -var result1 = queryable.LongCount("Income > 50");
                                                    -var result2 = queryable.LongCount("Income > @0", 50);
                                                    -var result3 = queryable.Select("Roles.LongCount()");
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LongCount(IQueryable, LambdaExpression)

                                                    -

                                                    Returns the number of elements in a sequence.

                                                    + +

                                                    OfType(IQueryable, Type)

                                                    +

                                                    Filters the elements of an IQueryable based on a specified type.

                                                    Declaration
                                                    -
                                                    public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static IQueryable OfType(this IQueryable source, Type type)
                                                    Parameters
                                                    @@ -3658,15 +4842,15 @@
                                                    Parameters
                                                    - + - - - - + + @@ -3681,26 +4865,27 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable that contains the elements to be counted.

                                                    +

                                                    An IQueryable whose elements to filter.

                                                    LambdaExpressionlambda

                                                    A cached Lambda Expression.

                                                    +
                                                    Typetype

                                                    The type to filter the elements of the sequence on.

                                                    Int64

                                                    The number of elements in the specified sequence that satisfies a condition.

                                                    +
                                                    IQueryable

                                                    A collection that contains the elements from source that have the type.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    LongCount(IQueryable, String, Object[])

                                                    -
                                                    + +

                                                    OrderBy(IQueryable, ParsingConfig, String, IComparer, Object[])

                                                    +

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static long LongCount([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -3713,19 +4898,34 @@
                                                    Parameters
                                                    - + - + - - - + + + + + + + + + + + + + - + - +
                                                    IQueryableIQueryable source

                                                    A sequence of values to order.

                                                    +
                                                    StringpredicateParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    IComparercomparer

                                                    The comparer to use.

                                                    +
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    @@ -3739,26 +4939,27 @@
                                                    Returns
                                                    - Int64 - + IOrderedQueryable +

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    OfType(IQueryable, ParsingConfig, String)

                                                    -

                                                    Filters the elements of an IQueryable based on a specified type.

                                                    + +

                                                    OrderBy(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName)
                                                    +
                                                    public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -3771,9 +4972,9 @@
                                                    Parameters
                                                    - + - @@ -3783,9 +4984,15 @@
                                                    Parameters
                                                    - - - + + + + + + + @@ -3800,27 +5007,32 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    An IQueryable whose elements to filter.

                                                    +

                                                    A sequence of values to order.

                                                    StringtypeName

                                                    The type to filter the elements of the sequence on.

                                                    +
                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    A collection that contains the elements from source that have the type.

                                                    +
                                                    IOrderedQueryable

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    +
                                                    Examples
                                                    +
                                                    var resultSingle = queryable.OrderBy("NumberProperty");
                                                    +var resultSingleDescending = queryable.OrderBy("NumberProperty DESC");
                                                    +var resultMultiple = queryable.OrderBy("NumberProperty, StringProperty DESC");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    OfType(IQueryable, String)

                                                    -

                                                    Filters the elements of an IQueryable based on a specified type.

                                                    + +

                                                    OrderBy(IQueryable, String, IComparer, Object[])

                                                    +

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] string typeName)
                                                    +
                                                    public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -3833,16 +5045,24 @@
                                                    Parameters
                                                    - + - + - - - + + + + + + + + + + + + +
                                                    IQueryableIQueryable source

                                                    An IQueryable whose elements to filter.

                                                    -
                                                    StringtypeName

                                                    The type to filter the elements of the sequence on.

                                                    -
                                                    Stringordering
                                                    IComparercomparer
                                                    Object[]args
                                                    @@ -3856,27 +5076,27 @@
                                                    Returns
                                                    - IQueryable -

                                                    A collection that contains the elements from source that have the type.

                                                    + IOrderedQueryable +

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    OfType(IQueryable, Type)

                                                    -

                                                    Filters the elements of an IQueryable based on a specified type.

                                                    + +

                                                    OrderBy(IQueryable, String, Object[])

                                                    +

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Type type)
                                                    +
                                                    public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -3889,16 +5109,19 @@
                                                    Parameters
                                                    - + - + - - - + + + + + + + +
                                                    IQueryableIQueryable source

                                                    An IQueryable whose elements to filter.

                                                    -
                                                    Typetype

                                                    The type to filter the elements of the sequence on.

                                                    -
                                                    Stringordering
                                                    Object[]args
                                                    @@ -3912,27 +5135,27 @@
                                                    Returns
                                                    - IQueryable -

                                                    A collection that contains the elements from source that have the type.

                                                    + IOrderedQueryable +

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    OrderBy(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    OrderBy<TSource>(IQueryable<TSource>, ParsingConfig, String, IComparer, Object[])

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, ParsingConfig config, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -3945,7 +5168,7 @@
                                                    Parameters
                                                    - + @@ -3957,15 +5180,21 @@
                                                    Parameters
                                                    - + - + + + + + + - @@ -3980,31 +5209,43 @@
                                                    Returns
                                                    - - + + + +
                                                    IQueryableIQueryable<TSource> source

                                                    A sequence of values to order.

                                                    StringString ordering

                                                    An expression string to indicate values to order by.

                                                    Object[]IComparercomparer

                                                    The comparer to use.

                                                    +
                                                    Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IOrderedQueryable

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    +
                                                    IOrderedQueryable<TSource>

                                                    A IQueryable<T> whose elements are sorted according to the specified ordering.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + +
                                                    NameDescription
                                                    TSource

                                                    The type of the elements of source.

                                                    -
                                                    Examples
                                                    -
                                                    var resultSingle = queryable.OrderBy("NumberProperty");
                                                    -var resultSingleDescending = queryable.OrderBy("NumberProperty DESC");
                                                    -var resultMultiple = queryable.OrderBy("NumberProperty, StringProperty DESC");
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    OrderBy(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    OrderBy<TSource>(IQueryable<TSource>, ParsingConfig, String, Object[])

                                                    +

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, ParsingConfig config, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -4017,19 +5258,28 @@
                                                    Parameters
                                                    - + - + + + + + + - + - + - + - +
                                                    IQueryableIQueryable<TSource> source

                                                    A sequence of values to order.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    StringString ordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    @@ -4043,26 +5293,48 @@
                                                    Returns
                                                    - IOrderedQueryable - + IOrderedQueryable<TSource> +

                                                    A IQueryable<T> whose elements are sorted according to the specified ordering.

                                                    + + + + +
                                                    Type Parameters
                                                    + + + + + + + + + + +
                                                    NameDescription
                                                    TSource

                                                    The type of the elements of source.

                                                    +
                                                    +
                                                    Examples
                                                    +
                                                    var resultSingle = queryable.OrderBy<User>("NumberProperty");
                                                    +var resultSingleDescending = queryable.OrderBy<User>("NumberProperty DESC");
                                                    +var resultMultiple = queryable.OrderBy<User>("NumberProperty, StringProperty");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    OrderBy<TSource>(IQueryable<TSource>, ParsingConfig, String, Object[])

                                                    +

                                                    OrderBy<TSource>(IQueryable<TSource>, String, IComparer, Object[])

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable<TSource> OrderBy<TSource>([NotNull] this IQueryable<TSource> source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -4075,25 +5347,25 @@
                                                    Parameters
                                                    - + - - - + + - - - + + - + @@ -4110,8 +5382,8 @@
                                                    Returns
                                                    - - + @@ -4132,25 +5404,21 @@
                                                    Type Parameters
                                                    IQueryable<TSource>IQueryable<TSource> source

                                                    A sequence of values to order.

                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    IComparercomparer

                                                    The comparer to use.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IOrderedQueryable<TSource>

                                                    A IQueryable<T> whose elements are sorted according to the specified ordering.

                                                    +
                                                    IOrderedQueryable<TSource>

                                                    A IQueryable<T> whose elements are sorted according to the specified ordering.

                                                    -
                                                    Examples
                                                    -
                                                    var resultSingle = queryable.OrderBy<User>("NumberProperty");
                                                    -var resultSingleDescending = queryable.OrderBy<User>("NumberProperty DESC");
                                                    -var resultMultiple = queryable.OrderBy<User>("NumberProperty, StringProperty");
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    OrderBy<TSource>(IQueryable<TSource>, String, Object[])

                                                    -
                                                    +

                                                    Sorts the elements of a sequence in ascending or descending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable<TSource> OrderBy<TSource>([NotNull] this IQueryable<TSource> source, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -4163,17 +5431,17 @@
                                                    Parameters
                                                    - + - + - + @@ -4189,8 +5457,9 @@
                                                    Returns
                                                    - - + +
                                                    IQueryable<TSource>IQueryable<TSource> source
                                                    StringString ordering
                                                    Object[]Object[] args
                                                    IOrderedQueryable<TSource>IOrderedQueryable<TSource>

                                                    A IQueryable<T> whose elements are sorted according to the specified ordering.

                                                    +
                                                    @@ -4205,16 +5474,17 @@
                                                    Type Parameters
                                                    TSource - +

                                                    The type of the elements of source.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Page(IQueryable, Int32, Int32)

                                                    @@ -4223,7 +5493,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize)
                                                    +
                                                    public static IQueryable Page(this IQueryable source, int page, int pageSize)
                                                    Parameters
                                                    @@ -4236,19 +5506,19 @@
                                                    Parameters
                                                    - + - + - + @@ -4265,18 +5535,18 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    The IQueryable to return elements from.

                                                    Int32Int32 page

                                                    The page to return.

                                                    Int32Int32 pageSize

                                                    The number of elements per page.

                                                    IQueryable

                                                    A IQueryable that contains the paged elements.

                                                    +
                                                    IQueryable

                                                    A IQueryable that contains the paged elements.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Page<TSource>(IQueryable<TSource>, Int32, Int32)

                                                    @@ -4285,7 +5555,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable<TSource> Page<TSource>([NotNull] this IQueryable<TSource> source, int page, int pageSize)
                                                    +
                                                    public static IQueryable<TSource> Page<TSource>(this IQueryable<TSource> source, int page, int pageSize)
                                                    Parameters
                                                    @@ -4298,19 +5568,19 @@
                                                    Parameters
                                                    - + - + - + @@ -4327,8 +5597,8 @@
                                                    Returns
                                                    - - + @@ -4351,19 +5621,19 @@
                                                    Type Parameters
                                                    IQueryable<TSource>IQueryable<TSource> source

                                                    The IQueryable to return elements from.

                                                    Int32Int32 page

                                                    The page to return.

                                                    Int32Int32 pageSize

                                                    The number of elements per page.

                                                    IQueryable<TSource>

                                                    A IQueryable<T> that contains the paged elements.

                                                    +
                                                    IQueryable<TSource>

                                                    A IQueryable<T> that contains the paged elements.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    PageResult(IQueryable, Int32, Int32)

                                                    +

                                                    PageResult(IQueryable, Int32, Int32, Nullable<Int32>)

                                                    Returns the elements as paged and include the CurrentPage, PageCount, PageSize and RowCount.

                                                    Declaration
                                                    -
                                                    public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize)
                                                    +
                                                    public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null)
                                                    Parameters
                                                    @@ -4376,21 +5646,27 @@
                                                    Parameters
                                                    - + - + - + + + + + + @@ -4413,19 +5689,19 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return elements from.

                                                    Int32Int32 page

                                                    The page to return.

                                                    Int32Int32 pageSize

                                                    The number of elements per page.

                                                    +
                                                    Nullable<Int32>rowCount

                                                    If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq Count().

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    PageResult<TSource>(IQueryable<TSource>, Int32, Int32)

                                                    +

                                                    PageResult<TSource>(IQueryable<TSource>, Int32, Int32, Nullable<Int32>)

                                                    Returns the elements as paged and include the CurrentPage, PageCount, PageSize and RowCount.

                                                    Declaration
                                                    -
                                                    public static PagedResult<TSource> PageResult<TSource>([NotNull] this IQueryable<TSource> source, int page, int pageSize)
                                                    +
                                                    public static PagedResult<TSource> PageResult<TSource>(this IQueryable<TSource> source, int page, int pageSize, int? rowCount = null)
                                                    Parameters
                                                    @@ -4438,21 +5714,27 @@
                                                    Parameters
                                                    - + - + - + + + + + + @@ -4491,10 +5773,10 @@
                                                    Type Parameters
                                                    IQueryable<TSource>IQueryable<TSource> source

                                                    The IQueryable to return elements from.

                                                    Int32Int32 page

                                                    The page to return.

                                                    Int32Int32 pageSize

                                                    The number of elements per page.

                                                    +
                                                    Nullable<Int32>rowCount

                                                    If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq Count().

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Reverse(IQueryable)

                                                    @@ -4503,7 +5785,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Reverse([NotNull] this IQueryable source)
                                                    +
                                                    public static IQueryable Reverse(this IQueryable source)
                                                    Parameters
                                                    @@ -4516,7 +5798,7 @@
                                                    Parameters
                                                    - + @@ -4533,18 +5815,18 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    A sequence of values to reverse.

                                                    IQueryable

                                                    A IQueryable whose elements correspond to those of the input sequence in reverse order.

                                                    +
                                                    IQueryable

                                                    A IQueryable whose elements correspond to those of the input sequence in reverse order.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Select(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -4553,7 +5835,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object[] args)
                                                    Parameters
                                                    @@ -4566,7 +5848,7 @@
                                                    Parameters
                                                    - + @@ -4578,13 +5860,13 @@
                                                    Parameters
                                                    - + - + @@ -4601,8 +5883,8 @@
                                                    Returns
                                                    - - + @@ -4613,10 +5895,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Select(IQueryable, ParsingConfig, Type, String, Object[])

                                                    @@ -4626,7 +5908,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable Select(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    StringString selector

                                                    A projection string expression to apply to each element.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a projection string on each element of source.

                                                    +
                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a projection string on each element of source.

                                                    @@ -4639,7 +5921,7 @@
                                                    Parameters
                                                    - + @@ -4651,19 +5933,19 @@
                                                    Parameters
                                                    - + - + - + @@ -4680,8 +5962,8 @@
                                                    Returns
                                                    - - + @@ -4691,18 +5973,19 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Select(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence into a new form.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable Select(this IQueryable source, string selector, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    TypeType resultType

                                                    The result type.

                                                    StringString selector

                                                    A projection string expression to apply to each element.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters.

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a projection string on each element of source.

                                                    +
                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a projection string on each element of source.

                                                    @@ -4715,17 +5998,17 @@
                                                    Parameters
                                                    - + - + - + @@ -4741,25 +6024,28 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString selector
                                                    Object[]Object[] args
                                                    IQueryableIQueryable

                                                    An IQueryable whose elements are the result of invoking a projection string on each element of source.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Select(IQueryable, Type, String, Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence into a new class of type TResult. +Details see http://solutionizing.net/category/linq/

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable Select(this IQueryable source, Type resultType, string selector, params object[] args)
                                                    Parameters
                                                    @@ -4772,22 +6058,22 @@
                                                    Parameters
                                                    - + - + - + - + @@ -4803,17 +6089,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    TypeType resultType
                                                    StringString selector
                                                    Object[]Object[] args
                                                    IQueryableIQueryable

                                                    An IQueryable whose elements are the result of invoking a projection string on each element of source.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Select<TResult>(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -4823,7 +6110,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable<TResult> Select<TResult>([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable<TResult> Select<TResult>(this IQueryable source, ParsingConfig config, string selector, params object[] args)
                                                    Parameters
                                                    @@ -4836,7 +6123,7 @@
                                                    Parameters
                                                    - + @@ -4848,13 +6135,13 @@
                                                    Parameters
                                                    - + - + @@ -4871,8 +6158,8 @@
                                                    Returns
                                                    - - + @@ -4898,18 +6185,20 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Select<TResult>(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence into a new class of type TResult. +Details see http://solutionizing.net/category/linq/.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable<TResult> Select<TResult>([NotNull] this IQueryable source, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable<TResult> Select<TResult>(this IQueryable source, string selector, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    StringString selector

                                                    A projection string expression to apply to each element.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters.

                                                    IQueryable<TResult>

                                                    An IQueryable<T> whose elements are the result of invoking a projection string on each element of source.

                                                    +
                                                    IQueryable<TResult>

                                                    An IQueryable<T> whose elements are the result of invoking a projection string on each element of source.

                                                    @@ -4922,17 +6211,17 @@
                                                    Parameters
                                                    - + - + - + @@ -4948,8 +6237,9 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString selector
                                                    Object[]Object[] args
                                                    IQueryable<TResult>IQueryable<TResult>

                                                    An IQueryable<T> whose elements are the result of invoking a projection string on each element of source.

                                                    +
                                                    @@ -4964,25 +6254,26 @@
                                                    Type Parameters
                                                    TResult - +

                                                    The type of the result.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, ParsingConfig, String, Object[])

                                                    -

                                                    Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence.

                                                    +

                                                    Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence.

                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object[] args)
                                                    Parameters
                                                    @@ -4995,7 +6286,7 @@
                                                    Parameters
                                                    - + @@ -5007,13 +6298,13 @@
                                                    Parameters
                                                    - + - + @@ -5030,8 +6321,8 @@
                                                    Returns
                                                    - - + @@ -5041,14 +6332,14 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, ParsingConfig, String, String, Object[], Object[])

                                                    -

                                                    Projects each element of a sequence to an IQueryable +

                                                    Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned.

                                                    @@ -5056,7 +6347,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string collectionSelector, string resultSelector, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    StringString selector

                                                    A projection string expression to apply to each element.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    +
                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    @@ -5069,7 +6360,7 @@
                                                    Parameters
                                                    - + @@ -5081,25 +6372,25 @@
                                                    Parameters
                                                    - + - + - + - + @@ -5116,8 +6407,8 @@
                                                    Returns
                                                    - - + @@ -5129,14 +6420,14 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, ParsingConfig, String, String, String, String, Object[], Object[])

                                                    -

                                                    Projects each element of a sequence to an IQueryable +

                                                    Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned.

                                                    @@ -5144,7 +6435,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string collectionSelector, string resultSelector, string collectionParameterName, string resultParameterName, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    StringString collectionSelector

                                                    A projection function to apply to each element of the input sequence.

                                                    StringString resultSelector

                                                    A projection function to apply to each element of each intermediate sequence. Should only use x and y as parameter names.

                                                    Object[]Object[] collectionSelectorArgs

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    Object[]Object[] resultSelectorArgs

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking the one-to-many +

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element.

                                                    @@ -5157,7 +6448,7 @@
                                                    Parameters
                                                    - + @@ -5169,37 +6460,37 @@
                                                    Parameters
                                                    - + - + - + - + - + - + @@ -5216,8 +6507,8 @@
                                                    Returns
                                                    - - + @@ -5229,19 +6520,19 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, ParsingConfig, Type, String, Object[])

                                                    -

                                                    Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence.

                                                    +

                                                    Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence.

                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    StringString collectionSelector

                                                    A projection function to apply to each element of the input sequence.

                                                    StringString resultSelector

                                                    A projection function to apply to each element of each intermediate sequence.

                                                    StringString collectionParameterName

                                                    The name from collectionParameter to use. Default is x.

                                                    StringString resultParameterName

                                                    The name from resultParameterName to use. Default is y.

                                                    Object[]Object[] collectionSelectorArgs

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    Object[]Object[] resultSelectorArgs

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking the one-to-many +

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element.

                                                    @@ -5254,7 +6545,7 @@
                                                    Parameters
                                                    - + @@ -5266,19 +6557,19 @@
                                                    Parameters
                                                    - + - + - + @@ -5295,8 +6586,8 @@
                                                    Returns
                                                    - - + @@ -5306,18 +6597,19 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, string selector, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    TypeType resultType

                                                    The result type.

                                                    StringString selector

                                                    A projection string expression to apply to each element.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    +
                                                    IQueryable

                                                    An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    @@ -5330,17 +6622,17 @@
                                                    Parameters
                                                    - + - + - + @@ -5356,25 +6648,30 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString selector
                                                    Object[]Object[] args
                                                    IQueryableIQueryable

                                                    An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, String, String, Object[], Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence to an IQueryable +and invokes a result selector function on each element therein. The resulting +values from each intermediate sequence are combined into a single, one-dimensional +sequence and returned.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs)
                                                    Parameters
                                                    @@ -5387,27 +6684,27 @@
                                                    Parameters
                                                    - + - + - + - + - + @@ -5423,25 +6720,32 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString collectionSelector
                                                    StringString resultSelector
                                                    Object[]Object[] collectionSelectorArgs
                                                    Object[]Object[] resultSelectorArgs
                                                    IQueryableIQueryable

                                                    An IQueryable whose elements are the result of invoking the one-to-many +projection function collectionSelector on each element of source and then mapping +each of those sequence elements and their corresponding source element to a result element.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, String, String, String, String, Object[], Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence to an IQueryable +and invokes a result selector function on each element therein. The resulting +values from each intermediate sequence are combined into a single, one-dimensional +sequence and returned.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, string collectionParameterName, string resultParameterName, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs)
                                                    Parameters
                                                    @@ -5454,37 +6758,37 @@
                                                    Parameters
                                                    - + - + - + - + - + - + - + @@ -5500,25 +6804,29 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString collectionSelector
                                                    StringString resultSelector
                                                    StringString collectionParameterName
                                                    StringString resultParameterName
                                                    Object[]Object[] collectionSelectorArgs
                                                    Object[]Object[] resultSelectorArgs
                                                    IQueryableIQueryable

                                                    An IQueryable whose elements are the result of invoking the one-to-many +projection function collectionSelector on each element of source and then mapping +each of those sequence elements and their corresponding source element to a result element.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany(IQueryable, Type, String, Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable SelectMany(this IQueryable source, Type resultType, string selector, params object[] args)
                                                    Parameters
                                                    @@ -5531,22 +6839,22 @@
                                                    Parameters
                                                    - + - + - + - + @@ -5562,26 +6870,27 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    TypeType resultType
                                                    StringString selector
                                                    Object[]Object[] args
                                                    IQueryableIQueryable

                                                    An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany<TResult>(IQueryable, ParsingConfig, String, Object[])

                                                    -

                                                    Projects each element of a sequence to an IQueryable<T> and combines the resulting sequences into one sequence.

                                                    +

                                                    Projects each element of a sequence to an IQueryable<T> and combines the resulting sequences into one sequence.

                                                    Declaration
                                                    -
                                                    public static IQueryable<TResult> SelectMany<TResult>([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable<TResult> SelectMany<TResult>(this IQueryable source, ParsingConfig config, string selector, params object[] args)
                                                    Parameters
                                                    @@ -5594,7 +6903,7 @@
                                                    Parameters
                                                    - + @@ -5606,13 +6915,13 @@
                                                    Parameters
                                                    - + - + @@ -5629,8 +6938,8 @@
                                                    Returns
                                                    - - + @@ -5656,18 +6965,19 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SelectMany<TResult>(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Projects each element of a sequence to an IQueryable<T> and combines the resulting sequences into one sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable<TResult> SelectMany<TResult>([NotNull] this IQueryable source, [NotNull] string selector, params object[] args)
                                                    +
                                                    public static IQueryable<TResult> SelectMany<TResult>(this IQueryable source, string selector, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of values to project.

                                                    StringString selector

                                                    A projection string expression to apply to each element.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable<TResult>

                                                    An IQueryable<T> whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    +
                                                    IQueryable<TResult>

                                                    An IQueryable<T> whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    @@ -5680,17 +6990,17 @@
                                                    Parameters
                                                    - + - + - + @@ -5706,8 +7016,9 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString selector
                                                    Object[]Object[] args
                                                    IQueryable<TResult>IQueryable<TResult>

                                                    An IQueryable<T> whose elements are the result of invoking a one-to-many projection function on each element of the input sequence.

                                                    +
                                                    @@ -5722,16 +7033,17 @@
                                                    Type Parameters
                                                    TResult - +

                                                    The type of the result.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Single(IQueryable)

                                                    @@ -5741,7 +7053,7 @@

                                                    Declaration
                                                    -
                                                    public static object Single([NotNull] this IQueryable source)
                                                    +
                                                    public static object Single(this IQueryable source)
                                                    Parameters
                                                    @@ -5754,9 +7066,9 @@
                                                    Parameters
                                                    - + - @@ -5771,7 +7083,7 @@
                                                    Returns
                                                    - + @@ -5779,10 +7091,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    A IQueryable to return the single element of.

                                                    +

                                                    A IQueryable to return the single element of.

                                                    ObjectObject

                                                    The single element of the input sequence.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Single(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -5792,7 +7104,7 @@

                                                    Declaration
                                                    -
                                                    public static object Single([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static object Single(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -5805,9 +7117,9 @@
                                                    Parameters
                                                    - + - @@ -5817,13 +7129,13 @@
                                                    Parameters
                                                    - + - + @@ -5840,7 +7152,7 @@
                                                    Returns
                                                    - + @@ -5848,10 +7160,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    The IQueryable to return the last element of.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Single(IQueryable, LambdaExpression)

                                                    @@ -5861,7 +7173,7 @@

                                                    Declaration
                                                    -
                                                    public static object Single([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static object Single(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -5874,13 +7186,13 @@
                                                    Parameters
                                                    - + - - + @@ -5897,7 +7209,7 @@
                                                    Returns
                                                    - + @@ -5905,18 +7217,20 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    The IQueryable to return the last element of.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Single(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Returns the only element of a sequence that satisfies a specified condition, and throws an exception if there +is not exactly one element in the sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static object Single([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static object Single(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -5929,17 +7243,17 @@
                                                    Parameters
                                                    - + - + - + @@ -5955,17 +7269,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SingleOrDefault(IQueryable)

                                                    @@ -5976,7 +7291,7 @@

                                                    Declaration
                                                    -
                                                    public static object SingleOrDefault([NotNull] this IQueryable source)
                                                    +
                                                    public static object SingleOrDefault(this IQueryable source)
                                                    Parameters
                                                    @@ -5989,9 +7304,9 @@
                                                    Parameters
                                                    - + - @@ -6006,7 +7321,7 @@
                                                    Returns
                                                    - + @@ -6014,10 +7329,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    A IQueryable to return the single element of.

                                                    +

                                                    A IQueryable to return the single element of.

                                                    ObjectObject

                                                    The single element of the input sequence, or default if the sequence contains no elements.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SingleOrDefault(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -6027,7 +7342,7 @@

                                                    Declaration
                                                    -
                                                    public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static object SingleOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -6040,9 +7355,9 @@
                                                    Parameters
                                                    - + - @@ -6052,13 +7367,13 @@
                                                    Parameters
                                                    - + - + @@ -6075,7 +7390,7 @@
                                                    Returns
                                                    - + @@ -6083,10 +7398,10 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    The IQueryable to return the last element of.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SingleOrDefault(IQueryable, LambdaExpression)

                                                    @@ -6096,7 +7411,7 @@

                                                    Declaration
                                                    -
                                                    public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static object SingleOrDefault(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    @@ -6109,13 +7424,13 @@
                                                    Parameters
                                                    - + - - + @@ -6132,7 +7447,7 @@
                                                    Returns
                                                    - + @@ -6140,18 +7455,20 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    The IQueryable to return the last element of.

                                                    +

                                                    The IQueryable to return the last element of.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SingleOrDefault(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Returns the only element of a sequence that satisfies a specified condition or a default value if the sequence +is empty; and throws an exception if there is not exactly one element in the sequence.

                                                    +
                                                    Declaration
                                                    -
                                                    public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static object SingleOrDefault(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -6164,17 +7481,17 @@
                                                    Parameters
                                                    - + - + - + @@ -6190,17 +7507,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    ObjectObject

                                                    The first element in source that passes the test in predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Skip(IQueryable, Int32)

                                                    @@ -6209,7 +7527,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Skip([NotNull] this IQueryable source, int count)
                                                    +
                                                    public static IQueryable Skip(this IQueryable source, int count)
                                                    Parameters
                                                    @@ -6222,13 +7540,13 @@
                                                    Parameters
                                                    - + - - + @@ -6245,18 +7563,18 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    A IQueryable to return elements from.

                                                    +

                                                    A IQueryable to return elements from.

                                                    Int32Int32 count

                                                    The number of elements to skip before returning the remaining elements.

                                                    IQueryable

                                                    A IQueryable that contains elements that occur after the specified index in the input sequence.

                                                    +
                                                    IQueryable

                                                    A IQueryable that contains elements that occur after the specified index in the input sequence.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SkipWhile(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -6265,7 +7583,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args)
                                                    +
                                                    public static IQueryable SkipWhile(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -6278,7 +7596,7 @@
                                                    Parameters
                                                    - + @@ -6290,13 +7608,13 @@
                                                    Parameters
                                                    - + - + @@ -6313,8 +7631,8 @@
                                                    Returns
                                                    - - + @@ -6326,18 +7644,19 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    SkipWhile(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
                                                    +
                                                    public static IQueryable SkipWhile(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence to check for being empty.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    An IQueryable that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate.

                                                    +
                                                    IQueryable

                                                    An IQueryable that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate.

                                                    @@ -6350,17 +7669,17 @@
                                                    Parameters
                                                    - + - + - + @@ -6376,17 +7695,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    IQueryableIQueryable

                                                    An IQueryable that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Sum(IQueryable)

                                                    @@ -6396,7 +7716,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static object Sum([NotNull] this IQueryable source)
                                                    +public static object Sum(this IQueryable source)
                                                    Parameters
                                                    @@ -6409,7 +7729,7 @@
                                                    Parameters
                                                    - + @@ -6426,7 +7746,7 @@
                                                    Returns
                                                    - + @@ -6439,10 +7759,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Sum(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -6452,7 +7772,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static object Sum([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +public static object Sum(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of numeric values to calculate the sum of.

                                                    ObjectObject

                                                    The sum of the values in the sequence.

                                                    @@ -6465,7 +7785,7 @@
                                                    Parameters
                                                    - + @@ -6477,13 +7797,13 @@
                                                    Parameters
                                                    - + - + @@ -6500,7 +7820,7 @@
                                                    Returns
                                                    - + @@ -6512,10 +7832,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Sum(IQueryable, LambdaExpression)

                                                    @@ -6525,7 +7845,7 @@

                                                    Declaration

                                                    [PublicAPI]
                                                    -public static object Sum([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +public static object Sum(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A sequence of numeric values to calculate the sum of.

                                                    StringString predicate

                                                    A function to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    ObjectObject

                                                    The sum of the values in the sequence.

                                                    @@ -6538,13 +7858,13 @@
                                                    Parameters
                                                    - + - + @@ -6561,7 +7881,7 @@
                                                    Returns
                                                    - + @@ -6569,19 +7889,267 @@
                                                    Returns
                                                    IQueryableIQueryable source

                                                    A sequence of numeric values to calculate the sum of.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A Lambda Expression.

                                                    ObjectObject

                                                    The sum of the values in the sequence.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Sum(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Computes the sum of a sequence of numeric values.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    [PublicAPI]
                                                    +public static object Sum(this IQueryable source, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource
                                                    Stringpredicate
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    Object

                                                    The sum of the values in the sequence.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    Take(IQueryable, Int32)

                                                    +

                                                    Returns a specified number of contiguous elements from the start of a sequence.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable Take(this IQueryable source, int count)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    The sequence to return elements from.

                                                    +
                                                    Int32count

                                                    The number of elements to return.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    A IQueryable that contains the specified number of elements from the start of source.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    TakeWhile(IQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Returns elements from a sequence as long as a specified condition is true.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable TakeWhile(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource

                                                    A sequence to check for being empty.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringpredicate

                                                    A function to test each element for a condition.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    An IQueryable that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes.

                                                    +
                                                    +
                                                    Examples
                                                    +
                                                    IQueryable queryable = employees.AsQueryable();
                                                    +var result1 = queryable.TakeWhile("Income > 50");
                                                    +var result2 = queryable.TakeWhile("Income > @0", 50);
                                                    + + + | + Improve this Doc + + + View Source + + +

                                                    TakeWhile(IQueryable, String, Object[])

                                                    +

                                                    Returns elements from a sequence as long as a specified condition is true.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable TakeWhile(this IQueryable source, string predicate, params object[] args)
                                                    +
                                                    +
                                                    Parameters
                                                    + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryablesource
                                                    Stringpredicate
                                                    Object[]args
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable

                                                    An IQueryable that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes.

                                                    +
                                                    + + | + Improve this Doc + + + View Source + + +

                                                    ThenBy(IOrderedQueryable, ParsingConfig, String, IComparer, Object[])

                                                    +

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    [PublicAPI]
                                                    -public static object Sum([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
                                                    +
                                                    public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -6594,19 +8162,34 @@
                                                    Parameters
                                                    - + - + - - - + + + + + + + + + + + + + - + - +
                                                    IQueryableIOrderedQueryable source

                                                    A sequence of values to order.

                                                    +
                                                    StringpredicateParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    IComparercomparer

                                                    The comparer to use.

                                                    +
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    @@ -6620,26 +8203,27 @@
                                                    Returns
                                                    - Object - + IOrderedQueryable +

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    Take(IQueryable, Int32)

                                                    -

                                                    Returns a specified number of contiguous elements from the start of a sequence.

                                                    + +

                                                    ThenBy(IOrderedQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IQueryable Take([NotNull] this IQueryable source, int count)
                                                    +
                                                    public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -6652,15 +8236,27 @@
                                                    Parameters
                                                    - + - - - - + + + + + + + + + + + + @@ -6675,27 +8271,33 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIOrderedQueryable source

                                                    The sequence to return elements from.

                                                    +

                                                    A sequence of values to order.

                                                    Int32count

                                                    The number of elements to return.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    Object[]args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    A IQueryable that contains the specified number of elements from the start of source.

                                                    +
                                                    IOrderedQueryable

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    +
                                                    Examples
                                                    +
                                                    var result = queryable.OrderBy("LastName");
                                                    +var resultSingle = result.OrderBy("NumberProperty");
                                                    +var resultSingleDescending = result.OrderBy("NumberProperty DESC");
                                                    +var resultMultiple = result.OrderBy("NumberProperty, StringProperty DESC");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    TakeWhile(IQueryable, ParsingConfig, String, Object[])

                                                    -

                                                    Returns elements from a sequence as long as a specified condition is true.

                                                    + +

                                                    ThenBy(IOrderedQueryable, String, IComparer, Object[])

                                                    +

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args)
                                                    +
                                                    public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -6708,28 +8310,24 @@
                                                    Parameters
                                                    - + - + - - - + + + - - - + + + - + - +
                                                    IQueryableIOrderedQueryable source

                                                    A sequence to check for being empty.

                                                    -
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    -
                                                    Stringordering
                                                    Stringpredicate

                                                    A function to test each element for a condition.

                                                    -
                                                    IComparercomparer
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    -
                                                    @@ -6743,31 +8341,27 @@
                                                    Returns
                                                    - IQueryable -

                                                    An IQueryable that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes.

                                                    + IOrderedQueryable +

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    -
                                                    Examples
                                                    -
                                                    IQueryable queryable = employees.AsQueryable();
                                                    -var result1 = queryable.TakeWhile("Income > 50");
                                                    -var result2 = queryable.TakeWhile("Income > @0", 50);
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                    TakeWhile(IQueryable, String, Object[])

                                                    -
                                                    + +

                                                    ThenBy(IOrderedQueryable, String, Object[])

                                                    +

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args)
                                                    +
                                                    public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -6780,17 +8374,17 @@
                                                    Parameters
                                                    - + - - + + - + @@ -6806,26 +8400,27 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIOrderedQueryable source
                                                    StringpredicateStringordering
                                                    Object[]Object[] args
                                                    IQueryableIOrderedQueryable

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    ThenBy(IOrderedQueryable, ParsingConfig, String, Object[])

                                                    +

                                                    ThenBy<TSource>(IOrderedQueryable<TSource>, ParsingConfig, String, IComparer, Object[])

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, ParsingConfig config, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -6838,7 +8433,7 @@
                                                    Parameters
                                                    - + @@ -6850,15 +8445,21 @@
                                                    Parameters
                                                    - + - + + + + + + - @@ -6873,32 +8474,43 @@
                                                    Returns
                                                    - - + + + +
                                                    IOrderedQueryableIOrderedQueryable<TSource> source

                                                    A sequence of values to order.

                                                    StringString ordering

                                                    An expression string to indicate values to order by.

                                                    Object[]IComparercomparer

                                                    The comparer to use.

                                                    +
                                                    Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IOrderedQueryable

                                                    A IQueryable whose elements are sorted according to the specified ordering.

                                                    +
                                                    IOrderedQueryable<TSource>

                                                    A IOrderedQueryable<T> whose elements are sorted according to the specified ordering.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + +
                                                    NameDescription
                                                    TSource

                                                    The type of the elements of source.

                                                    -
                                                    Examples
                                                    -
                                                    var result = queryable.OrderBy("LastName");
                                                    -var resultSingle = result.OrderBy("NumberProperty");
                                                    -var resultSingleDescending = result.OrderBy("NumberProperty DESC");
                                                    -var resultMultiple = result.OrderBy("NumberProperty, StringProperty DESC");
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    ThenBy(IOrderedQueryable, String, Object[])

                                                    -
                                                    +

                                                    ThenBy<TSource>(IOrderedQueryable<TSource>, ParsingConfig, String, Object[])

                                                    +

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, ParsingConfig config, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -6911,19 +8523,28 @@
                                                    Parameters
                                                    - + - + + + + + + - + - + - + - +
                                                    IOrderedQueryableIOrderedQueryable<TSource> source

                                                    A sequence of values to order.

                                                    +
                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    StringString ordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    +
                                                    @@ -6937,26 +8558,49 @@
                                                    Returns
                                                    - IOrderedQueryable - + IOrderedQueryable<TSource> +

                                                    A IOrderedQueryable<T> whose elements are sorted according to the specified ordering.

                                                    + + + + +
                                                    Type Parameters
                                                    + + + + + + + + + + +
                                                    NameDescription
                                                    TSource

                                                    The type of the elements of source.

                                                    +
                                                    +
                                                    Examples
                                                    +
                                                    var result = queryable.OrderBy<User>("LastName");
                                                    +var resultSingle = result.ThenBy<User>("NumberProperty");
                                                    +var resultSingleDescending = result.ThenBy<User>("NumberProperty DESC");
                                                    +var resultMultiple = result.ThenBy<User>("NumberProperty, StringProperty");
                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source -

                                                    ThenBy<TSource>(IOrderedQueryable<TSource>, ParsingConfig, String, Object[])

                                                    +

                                                    ThenBy<TSource>(IOrderedQueryable<TSource>, String, IComparer, Object[])

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable<TSource> ThenBy<TSource>([NotNull] this IOrderedQueryable<TSource> source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, string ordering, IComparer comparer, params object[] args)
                                                    Parameters
                                                    @@ -6969,25 +8613,25 @@
                                                    Parameters
                                                    - + - - - + + - - - + + - + @@ -7004,8 +8648,8 @@
                                                    Returns
                                                    - - + @@ -7026,26 +8670,21 @@
                                                    Type Parameters
                                                    IOrderedQueryable<TSource>IOrderedQueryable<TSource> source

                                                    A sequence of values to order.

                                                    ParsingConfigconfig

                                                    The ParsingConfig.

                                                    +
                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    Stringordering

                                                    An expression string to indicate values to order by.

                                                    +
                                                    IComparercomparer

                                                    The comparer to use.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IOrderedQueryable<TSource>

                                                    A IOrderedQueryable<T> whose elements are sorted according to the specified ordering.

                                                    +
                                                    IOrderedQueryable<TSource>

                                                    A IOrderedQueryable<T> whose elements are sorted according to the specified ordering.

                                                    -
                                                    Examples
                                                    -
                                                    var result = queryable.OrderBy<User>("LastName");
                                                    -var resultSingle = result.ThenBy<User>("NumberProperty");
                                                    -var resultSingleDescending = result.ThenBy<User>("NumberProperty DESC");
                                                    -var resultMultiple = result.ThenBy<User>("NumberProperty, StringProperty");
                                                    - | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    ThenBy<TSource>(IOrderedQueryable<TSource>, String, Object[])

                                                    -
                                                    +

                                                    Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IOrderedQueryable<TSource> ThenBy<TSource>([NotNull] this IOrderedQueryable<TSource> source, [NotNull] string ordering, params object[] args)
                                                    +
                                                    public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, string ordering, params object[] args)
                                                    Parameters
                                                    @@ -7058,17 +8697,17 @@
                                                    Parameters
                                                    - + - + - + @@ -7084,8 +8723,9 @@
                                                    Returns
                                                    - - + +
                                                    IOrderedQueryable<TSource>IOrderedQueryable<TSource> source
                                                    StringString ordering
                                                    Object[]Object[] args
                                                    IOrderedQueryable<TSource>IOrderedQueryable<TSource>

                                                    A IOrderedQueryable<T> whose elements are sorted according to the specified ordering.

                                                    +
                                                    @@ -7100,16 +8740,17 @@
                                                    Type Parameters
                                                    TSource - +

                                                    The type of the elements of source.

                                                    + | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Where(IQueryable, ParsingConfig, String, Object[])

                                                    @@ -7118,7 +8759,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -7131,9 +8772,9 @@
                                                    Parameters
                                                    - + - @@ -7143,13 +8784,13 @@
                                                    Parameters
                                                    - + - + @@ -7166,8 +8807,8 @@
                                                    Returns
                                                    - - + @@ -7181,10 +8822,10 @@
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Where(IQueryable, LambdaExpression)

                                                    @@ -7193,7 +8834,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable Where([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda)
                                                    +
                                                    public static IQueryable Where(this IQueryable source, LambdaExpression lambda)
                                                    Parameters
                                                    IQueryableIQueryable source

                                                    A IQueryable to filter.

                                                    +

                                                    A IQueryable to filter.

                                                    StringString predicate

                                                    An expression string to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable

                                                    A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate.

                                                    +
                                                    IQueryable

                                                    A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate.

                                                    @@ -7206,13 +8847,13 @@
                                                    Parameters
                                                    - + - - + @@ -7229,26 +8870,27 @@
                                                    Returns
                                                    - - +
                                                    IQueryableIQueryable source

                                                    A IQueryable to filter.

                                                    +

                                                    A IQueryable to filter.

                                                    LambdaExpressionLambdaExpression lambda

                                                    A cached Lambda Expression.

                                                    IQueryable

                                                    A IQueryable that contains elements from the input sequence that satisfy the condition specified by LambdaExpression.

                                                    +
                                                    IQueryable

                                                    A IQueryable that contains elements from the input sequence that satisfy the condition specified by LambdaExpression.

                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Where(IQueryable, String, Object[])

                                                    -
                                                    +

                                                    Filters a sequence of values based on a predicate.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static IQueryable Where(this IQueryable source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -7261,17 +8903,17 @@
                                                    Parameters
                                                    - + - + - + @@ -7287,17 +8929,18 @@
                                                    Returns
                                                    - - + +
                                                    IQueryableIQueryable source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    IQueryableIQueryable

                                                    A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate.

                                                    +
                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                    Where<TSource>(IQueryable<TSource>, ParsingConfig, String, Object[])

                                                    @@ -7306,7 +8949,7 @@

                                                    Declaration
                                                    -
                                                    public static IQueryable<TSource> Where<TSource>([NotNull] this IQueryable<TSource> source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, ParsingConfig config, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -7319,9 +8962,9 @@
                                                    Parameters
                                                    - + - @@ -7331,13 +8974,13 @@
                                                    Parameters
                                                    - + - + @@ -7354,8 +8997,8 @@
                                                    Returns
                                                    - - + @@ -7385,18 +9028,89 @@
                                                    | - Improve this Doc + Improve this Doc + + + View Source + + +

                                                    Where<TSource>(IQueryable<TSource>, LambdaExpression)

                                                    +

                                                    Filters a sequence of values based on a predicate.

                                                    +
                                                    +
                                                    +
                                                    Declaration
                                                    +
                                                    +
                                                    public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, LambdaExpression lambda)
                                                    +
                                                    +
                                                    Parameters
                                                    +
                                                    IQueryable<TSource>IQueryable<TSource> source

                                                    A IQueryable<T> to filter.

                                                    +

                                                    A IQueryable<T> to filter.

                                                    StringString predicate

                                                    An expression string to test each element for a condition.

                                                    Object[]Object[] args

                                                    An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.

                                                    IQueryable<TSource>

                                                    A IQueryable<T> that contains elements from the input sequence that satisfy the condition specified by predicate.

                                                    +
                                                    IQueryable<TSource>

                                                    A IQueryable<T> that contains elements from the input sequence that satisfy the condition specified by predicate.

                                                    + + + + + + + + + + + + + + + + + + + +
                                                    TypeNameDescription
                                                    IQueryable<TSource>source
                                                    LambdaExpressionlambda

                                                    A cached Lambda Expression.

                                                    +
                                                    +
                                                    Returns
                                                    + + + + + + + + + + + + + +
                                                    TypeDescription
                                                    IQueryable<TSource>

                                                    A IQueryable that contains elements from the input sequence that satisfy the condition specified by LambdaExpression.

                                                    +
                                                    +
                                                    Type Parameters
                                                    + + + + + + + + + + + + + +
                                                    NameDescription
                                                    TSource
                                                    + + | + Improve this Doc - View Source + View Source

                                                    Where<TSource>(IQueryable<TSource>, String, Object[])

                                                    -
                                                    +

                                                    Filters a sequence of values based on a predicate.

                                                    +
                                                    Declaration
                                                    -
                                                    public static IQueryable<TSource> Where<TSource>([NotNull] this IQueryable<TSource> source, [NotNull] string predicate, params object[] args)
                                                    +
                                                    public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, string predicate, params object[] args)
                                                    Parameters
                                                    @@ -7409,17 +9123,17 @@
                                                    Parameters
                                                    - + - + - + @@ -7435,8 +9149,9 @@
                                                    Returns
                                                    - - + +
                                                    IQueryable<TSource>IQueryable<TSource> source
                                                    StringString predicate
                                                    Object[]Object[] args
                                                    IQueryable<TSource>IQueryable<TSource>

                                                    A IQueryable<T> that contains elements from the input sequence that satisfy the condition specified by predicate.

                                                    +
                                                    @@ -7451,7 +9166,8 @@
                                                    Type Parameters
                                                    TSource - +

                                                    The type of the elements of source.

                                                    + @@ -7463,15 +9179,16 @@
                                                    Type Parameters
                                                    diff --git a/docs/api/System.Linq.Dynamic.Core.Exceptions.ParseException.html b/docs/api/System.Linq.Dynamic.Core.Exceptions.ParseException.html index 8bda5a3b..f0d5a42d 100644 --- a/docs/api/System.Linq.Dynamic.Core.Exceptions.ParseException.html +++ b/docs/api/System.Linq.Dynamic.Core.Exceptions.ParseException.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                    -
                                                    +
                                                    Search Results for

                                                    -
                                                      +
                                                        Inheritance
                                                        - - + +
                                                        ParseException
                                                        -
                                                        +
                                                        Namespace: System.Linq.Dynamic.Core.Exceptions
                                                        @@ -156,10 +156,10 @@

                                                        Constructors

                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                        ParseException(String, Int32)

                                                        @@ -181,13 +181,13 @@
                                                        Parameters
                                                        - String + String message

                                                        The message that describes the error.

                                                        - Int32 + Int32 position

                                                        The location in the parsed string that produced the ParseException

                                                        @@ -198,10 +198,10 @@

                                                        Properties

                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                        Position

                                                        @@ -222,7 +222,7 @@
                                                        Property Value
                                                        - Int32 + Int32 @@ -231,14 +231,14 @@

                                                        Methods

                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                        GetObjectData(SerializationInfo, StreamingContext)

                                                        -

                                                        When overridden in a derived class, sets the SerializationInfo with information about the exception.

                                                        +

                                                        When overridden in a derived class, sets the SerializationInfo with information about the exception.

                                                        Declaration
                                                        @@ -256,27 +256,27 @@
                                                        Parameters
                                                        - SerializationInfo + SerializationInfo info -

                                                        The SerializationInfo that holds the serialized object data about the exception being thrown.

                                                        +

                                                        The SerializationInfo that holds the serialized object data about the exception being thrown.

                                                        - StreamingContext + StreamingContext context -

                                                        The StreamingContext that contains contextual information about the source or destination.

                                                        +

                                                        The StreamingContext that contains contextual information about the source or destination.

                                                        Overrides
                                                        - + | - Improve this Doc + Improve this Doc - View Source + View Source

                                                        ToString()

                                                        @@ -297,20 +297,20 @@
                                                        Returns
                                                        - String + String

                                                        A string representation of the current exception.

                                                        Overrides
                                                        - +

                                                        Implements

                                                        @@ -320,15 +320,16 @@

                                                        Implements

                                                        diff --git a/docs/api/System.Linq.Dynamic.Core.Exceptions.html b/docs/api/System.Linq.Dynamic.Core.Exceptions.html index 3090922f..41dd7b27 100644 --- a/docs/api/System.Linq.Dynamic.Core.Exceptions.html +++ b/docs/api/System.Linq.Dynamic.Core.Exceptions.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                        -
                                                        +
                                                        Search Results for

                                                        -
                                                          +
                                                            diff --git a/docs/api/System.Linq.Dynamic.Core.ExtensibilityPoint.html b/docs/api/System.Linq.Dynamic.Core.ExtensibilityPoint.html index 399088d2..e76596e5 100644 --- a/docs/api/System.Linq.Dynamic.Core.ExtensibilityPoint.html +++ b/docs/api/System.Linq.Dynamic.Core.ExtensibilityPoint.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                            -
                                                            +
                                                            Search Results for

                                                            -
                                                              +
                                                                Inheritance
                                                                -
                                                                +
                                                                ExtensibilityPoint
                                                                Namespace: System.Linq.Dynamic.Core
                                                                @@ -126,10 +126,10 @@

                                                                Fields

                                                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                QueryOptimizer

                                                                Place to optimize your queries. Example: Add a reference to Nuget package Linq.Expression.Optimizer @@ -150,7 +150,7 @@

                                                                Field Value
                                                                - Func<Expression, Expression> + Func<Expression, Expression> @@ -163,15 +163,16 @@
                                                                Field Value
                                                                diff --git a/docs/api/System.Linq.Dynamic.Core.GroupResult.html b/docs/api/System.Linq.Dynamic.Core.GroupResult.html index d47f44a0..7f0f20fb 100644 --- a/docs/api/System.Linq.Dynamic.Core.GroupResult.html +++ b/docs/api/System.Linq.Dynamic.Core.GroupResult.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                -
                                                                +
                                                                Search Results for

                                                                -
                                                                  +
                                                                    Inheritance
                                                                    - +
                                                                    GroupResult
                                                                    Namespace: System.Linq.Dynamic.Core
                                                                    @@ -122,10 +122,10 @@

                                                                    Properties

                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                    Count

                                                                    @@ -146,17 +146,17 @@
                                                                    Property Value
                                                                    - Int32 + Int32 | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                    Items

                                                                    @@ -177,17 +177,17 @@
                                                                    Property Value
                                                                    - IEnumerable + IEnumerable | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                    Key

                                                                    @@ -208,17 +208,17 @@
                                                                    Property Value
                                                                    - Object + Object | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                    Subgroups

                                                                    @@ -239,7 +239,7 @@
                                                                    Property Value
                                                                    - IEnumerable<GroupResult> + IEnumerable<GroupResult> @@ -248,14 +248,14 @@

                                                                    Methods

                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                    ToString()

                                                                    -

                                                                    Returns a String showing the key of the group and the number of items in the group.

                                                                    +

                                                                    Returns a String showing the key of the group and the number of items in the group.

                                                                    Declaration
                                                                    @@ -272,14 +272,14 @@
                                                                    Returns
                                                                    - String -

                                                                    A String that represents this instance.

                                                                    + String +

                                                                    A String that represents this instance.

                                                                    Overrides
                                                                    - +
                                                                    @@ -288,15 +288,16 @@
                                                                    Overrides
                                                                    diff --git a/docs/api/System.Linq.Dynamic.Core.IAssemblyHelper.html b/docs/api/System.Linq.Dynamic.Core.IAssemblyHelper.html index e4dfb733..63532d00 100644 --- a/docs/api/System.Linq.Dynamic.Core.IAssemblyHelper.html +++ b/docs/api/System.Linq.Dynamic.Core.IAssemblyHelper.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                    -
                                                                    +
                                                                    Search Results for

                                                                    -
                                                                      +
                                                                        diff --git a/docs/api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html b/docs/api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html index 66a829de..9888fb23 100644 --- a/docs/api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html +++ b/docs/api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                        -
                                                                        +
                                                                        Search Results for

                                                                        -
                                                                          +
                                                                            Declaration
                                                                            -
                                                                            bool SupportsLinqToObjects([NotNull] IQueryable query, [CanBeNull] IQueryProvider provider = null)
                                                                            +
                                                                            bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null)
                                                                            Parameters
                                                                            @@ -121,13 +121,13 @@
                                                                            Parameters
                                                                            - + - + @@ -144,7 +144,7 @@
                                                                            Returns
                                                                            - + @@ -158,15 +158,16 @@
                                                                            Returns
                                                                            diff --git a/docs/api/System.Linq.Dynamic.Core.PagedResult-1.html b/docs/api/System.Linq.Dynamic.Core.PagedResult-1.html index ebc7860a..17a4d6b2 100644 --- a/docs/api/System.Linq.Dynamic.Core.PagedResult-1.html +++ b/docs/api/System.Linq.Dynamic.Core.PagedResult-1.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                            -
                                                                            +
                                                                            Search Results for

                                                                            -
                                                                              +
                                                                                Inheritance
                                                                                - +
                                                                                PagedResult<TSource>
                                                                                @@ -107,25 +107,25 @@
                                                                                Inherited Members
                                                                                PagedResult.RowCount
                                                                                Namespace: System.Linq.Dynamic.Core
                                                                                @@ -154,10 +154,10 @@

                                                                                Properties

                                                                                | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                Queryable

                                                                                @@ -178,7 +178,7 @@
                                                                                Property Value
                                                                                - + @@ -192,15 +192,16 @@
                                                                                Property Value
                                                                                diff --git a/docs/api/System.Linq.Dynamic.Core.PagedResult.html b/docs/api/System.Linq.Dynamic.Core.PagedResult.html index d708b9a3..7f73476b 100644 --- a/docs/api/System.Linq.Dynamic.Core.PagedResult.html +++ b/docs/api/System.Linq.Dynamic.Core.PagedResult.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                -
                                                                                +
                                                                                Search Results for

                                                                                -
                                                                                  +
                                                                                    Inheritance
                                                                                    - +
                                                                                    PagedResult
                                                                                    Namespace: System.Linq.Dynamic.Core
                                                                                    @@ -126,10 +126,10 @@

                                                                                    Properties

                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                    CurrentPage

                                                                                    @@ -150,7 +150,7 @@
                                                                                    Property Value
                                                                                    - + @@ -158,10 +158,10 @@
                                                                                    Property Value
                                                                                    IQueryableIQueryable query

                                                                                    The query to check.

                                                                                    IQueryProviderIQueryProvider provider

                                                                                    The provider to check (can be null).

                                                                                    BooleanBoolean

                                                                                    true/false

                                                                                    IQueryable<TSource>IQueryable<TSource>

                                                                                    The queryable.

                                                                                    Int32Int32

                                                                                    The current page.

                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                    PageCount

                                                                                    @@ -182,7 +182,7 @@
                                                                                    Property Value
                                                                                    - Int32 + Int32

                                                                                    The page count.

                                                                                    @@ -190,10 +190,10 @@
                                                                                    Property Value
                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                    PageSize

                                                                                    @@ -214,7 +214,7 @@
                                                                                    Property Value
                                                                                    - Int32 + Int32

                                                                                    The size of the page.

                                                                                    @@ -222,10 +222,10 @@
                                                                                    Property Value
                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                    Queryable

                                                                                    @@ -246,7 +246,7 @@
                                                                                    Property Value
                                                                                    - IQueryable + IQueryable

                                                                                    The queryable.

                                                                                    @@ -254,10 +254,10 @@
                                                                                    Property Value
                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                    RowCount

                                                                                    @@ -278,7 +278,7 @@
                                                                                    Property Value
                                                                                    - Int32 + Int32

                                                                                    The row count.

                                                                                    @@ -292,15 +292,16 @@
                                                                                    Property Value
                                                                                    diff --git a/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html b/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html index 6f62eb0e..77dc984b 100644 --- a/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html +++ b/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                    -
                                                                                    +
                                                                                    Search Results for

                                                                                    -
                                                                                      +
                                                                                        Inheritance
                                                                                        - +
                                                                                        ExpressionParser
                                                                                        Namespace: System.Linq.Dynamic.Core.Parser
                                                                                        @@ -125,10 +125,10 @@

                                                                                        Constructors

                                                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                        ExpressionParser(ParameterExpression[], String, Object[], ParsingConfig)

                                                                                        @@ -137,7 +137,7 @@

                                                                                        Declaration
                                                                                        -
                                                                                        public ExpressionParser([CanBeNull] ParameterExpression[] parameters, [NotNull] string expression, [CanBeNull] object[] values, [CanBeNull] ParsingConfig parsingConfig)
                                                                                        +
                                                                                        public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, ParsingConfig parsingConfig)
                                                                                        Parameters
                                                                                        @@ -150,19 +150,19 @@
                                                                                        Parameters
                                                                                        - + - + - + @@ -179,10 +179,10 @@

                                                                                        Properties

                                                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                        ItName

                                                                                        @@ -203,17 +203,17 @@
                                                                                        Property Value
                                                                                        - +
                                                                                        ParameterExpression[]ParameterExpression[] parameters

                                                                                        The parameters.

                                                                                        StringString expression

                                                                                        The expression.

                                                                                        Object[]Object[] values

                                                                                        The values.

                                                                                        StringString
                                                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                        LastLambdaItName

                                                                                        @@ -238,7 +238,7 @@
                                                                                        Property Value
                                                                                        - String + String @@ -247,10 +247,10 @@

                                                                                        Methods

                                                                                        | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                        Parse(Type, Boolean)

                                                                                        @@ -259,7 +259,7 @@

                                                                                        Declaration
                                                                                        -
                                                                                        public Expression Parse([CanBeNull] Type resultType, bool createParameterCtor = true)
                                                                                        +
                                                                                        public Expression Parse(Type resultType, bool createParameterCtor = true)
                                                                                        Parameters
                                                                                        @@ -272,13 +272,13 @@
                                                                                        Parameters
                                                                                        - + - + @@ -295,7 +295,7 @@
                                                                                        Returns
                                                                                        - + @@ -309,15 +309,16 @@
                                                                                        Returns
                                                                                        diff --git a/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html b/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html index 8bc43fa5..327c29fe 100644 --- a/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html +++ b/docs/api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                        -
                                                                                        +
                                                                                        Search Results for

                                                                                        -
                                                                                          +
                                                                                            - + - + - + - + - + - + - + - +
                                                                                            TypeType resultType

                                                                                            Type of the result.

                                                                                            BooleanBoolean createParameterCtor

                                                                                            if set to true [create parameter ctor].

                                                                                            ExpressionExpression

                                                                                            Expression

                                                                                            ExpressionExpression expr

                                                                                            Source expression

                                                                                            +
                                                                                            TypeType type

                                                                                            Destination data type to promote

                                                                                            +
                                                                                            BooleanBoolean exact

                                                                                            If the match must be exact

                                                                                            +
                                                                                            BooleanBoolean convertExpr

                                                                                            Convert expression

                                                                                            +
                                                                                            @@ -219,8 +225,9 @@
                                                                                            Returns
                                                                                            - Expression - + Expression +

                                                                                            The promoted Expression or null.

                                                                                            + @@ -236,15 +243,16 @@

                                                                                            Implements

                                                                                            diff --git a/docs/api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html b/docs/api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html index dd7daf3d..0f9adb0f 100644 --- a/docs/api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html +++ b/docs/api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                            -
                                                                                            +
                                                                                            Search Results for

                                                                                            -
                                                                                              +
                                                                                                diff --git a/docs/api/System.Linq.Dynamic.Core.Parser.NumberParser.html b/docs/api/System.Linq.Dynamic.Core.Parser.NumberParser.html index 0913cc44..b5e86767 100644 --- a/docs/api/System.Linq.Dynamic.Core.Parser.NumberParser.html +++ b/docs/api/System.Linq.Dynamic.Core.Parser.NumberParser.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                                -
                                                                                                +
                                                                                                Search Results for

                                                                                                -
                                                                                                  +
                                                                                                    Inheritance
                                                                                                    - +
                                                                                                    NumberParser
                                                                                                    Namespace: System.Linq.Dynamic.Core.Parser
                                                                                                    @@ -125,10 +125,10 @@

                                                                                                    Constructors

                                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                    NumberParser(ParsingConfig)

                                                                                                    @@ -161,10 +161,65 @@

                                                                                                    Methods

                                                                                                    | - Improve this Doc + Improve this Doc - View Source + View Source + + +

                                                                                                    ParseIntegerLiteral(Int32, String)

                                                                                                    +

                                                                                                    Tries to parse the text into a IntegerLiteral ConstantExpression.

                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    Declaration
                                                                                                    +
                                                                                                    +
                                                                                                    public Expression ParseIntegerLiteral(int tokenPosition, string text)
                                                                                                    +
                                                                                                    +
                                                                                                    Parameters
                                                                                                    + + + + + + + + + + + + + + + + + + + + +
                                                                                                    TypeNameDescription
                                                                                                    Int32tokenPosition

                                                                                                    The current token position (needed for error reporting).

                                                                                                    +
                                                                                                    Stringtext

                                                                                                    The text.

                                                                                                    +
                                                                                                    +
                                                                                                    Returns
                                                                                                    + + + + + + + + + + + + + +
                                                                                                    TypeDescription
                                                                                                    Expression
                                                                                                    + + | + Improve this Doc + + + View Source

                                                                                                    ParseNumber(String, Type)

                                                                                                    @@ -186,13 +241,13 @@
                                                                                                    Parameters
                                                                                                    - String + String text

                                                                                                    The text.

                                                                                                    - Type + Type type

                                                                                                    The type.

                                                                                                    @@ -209,7 +264,126 @@
                                                                                                    Returns
                                                                                                    - Object + Object + + + + + + | + Improve this Doc + + + View Source + + +

                                                                                                    ParseRealLiteral(String, Char, Boolean)

                                                                                                    +

                                                                                                    Parse the text into a Real ConstantExpression.

                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    Declaration
                                                                                                    +
                                                                                                    +
                                                                                                    public Expression ParseRealLiteral(string text, char qualifier, bool stripQualifier)
                                                                                                    +
                                                                                                    +
                                                                                                    Parameters
                                                                                                    + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                    TypeNameDescription
                                                                                                    Stringtext
                                                                                                    Charqualifier
                                                                                                    BooleanstripQualifier
                                                                                                    +
                                                                                                    Returns
                                                                                                    + + + + + + + + + + + + + +
                                                                                                    TypeDescription
                                                                                                    Expression
                                                                                                    + + | + Improve this Doc + + + View Source + + +

                                                                                                    TryParseNumber(String, Type, out Object)

                                                                                                    +

                                                                                                    Tries to parse the number (text) into the specified type.

                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    Declaration
                                                                                                    +
                                                                                                    +
                                                                                                    public bool TryParseNumber(string text, Type type, out object result)
                                                                                                    +
                                                                                                    +
                                                                                                    Parameters
                                                                                                    + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                    TypeNameDescription
                                                                                                    Stringtext

                                                                                                    The text.

                                                                                                    +
                                                                                                    Typetype

                                                                                                    The type.

                                                                                                    +
                                                                                                    Objectresult

                                                                                                    The result.

                                                                                                    +
                                                                                                    +
                                                                                                    Returns
                                                                                                    + + + + + + + + + + @@ -222,15 +396,16 @@
                                                                                                    Returns
                                                                                                    diff --git a/docs/api/System.Linq.Dynamic.Core.Parser.html b/docs/api/System.Linq.Dynamic.Core.Parser.html index bebdbb3e..4d648ac1 100644 --- a/docs/api/System.Linq.Dynamic.Core.Parser.html +++ b/docs/api/System.Linq.Dynamic.Core.Parser.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                                    -
                                                                                                    +
                                                                                                    Search Results for

                                                                                                    -
                                                                                                      +
                                                                                                        diff --git a/docs/api/System.Linq.Dynamic.Core.ParsingConfig.html b/docs/api/System.Linq.Dynamic.Core.ParsingConfig.html index 0d0ba303..7f25ff80 100644 --- a/docs/api/System.Linq.Dynamic.Core.ParsingConfig.html +++ b/docs/api/System.Linq.Dynamic.Core.ParsingConfig.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                                        -
                                                                                                        +
                                                                                                        Search Results for

                                                                                                        -
                                                                                                          +
                                                                                                            Inheritance
                                                                                                            -
                                                                                                            +
                                                                                                            ParsingConfig
                                                                                                            Namespace: System.Linq.Dynamic.Core
                                                                                                            @@ -125,15 +125,15 @@

                                                                                                            Properties

                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            AllowNewToEvaluateAnyType

                                                                                                            Allows the New() keyword to evaluate any available Type.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -150,23 +150,23 @@
                                                                                                            Property Value
                                                                                                            - +
                                                                                                            TypeDescription
                                                                                                            Boolean
                                                                                                            BooleanBoolean
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            AreContextKeywordsEnabled

                                                                                                            Determines if the context keywords (it, parent, and root) are valid and usable inside a Dynamic Linq string expression.
                                                                                                            Does not affect the usability of the equivalent context symbols ($, ^ and ~).

                                                                                                            -

                                                                                                            Default value is true.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -183,17 +183,17 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            CustomTypeProvider

                                                                                                            @@ -221,16 +221,16 @@
                                                                                                            Property Value
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            DateTimeIsParsedAsUTC

                                                                                                            By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. Use this flag to parse all DateTime strings as UTC.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -247,17 +247,17 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            Default

                                                                                                            @@ -285,10 +285,41 @@
                                                                                                            Property Value
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source + + +

                                                                                                            DefaultCosmosDb

                                                                                                            +

                                                                                                            Default ParsingConfig for CosmosDb

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            Declaration
                                                                                                            +
                                                                                                            +
                                                                                                            public static ParsingConfig DefaultCosmosDb { get; }
                                                                                                            +
                                                                                                            +
                                                                                                            Property Value
                                                                                                            + + + + + + + + + + + + + +
                                                                                                            TypeDescription
                                                                                                            ParsingConfig
                                                                                                            + + | + Improve this Doc + + + View Source

                                                                                                            DefaultEFCore21

                                                                                                            @@ -316,17 +347,17 @@
                                                                                                            Property Value
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            DisableMemberAccessToIndexAccessorFallback

                                                                                                            By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use this flag to disable this behaviour and have parsing fail when parsing an expression where a member access on a non existing member happens.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -343,24 +374,24 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            EvaluateGroupByAtDatabase

                                                                                                            Gets or sets a value indicating whether the EntityFramework version supports evaluating GroupBy at database level. See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation

                                                                                                            Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -377,17 +408,17 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            ExpressionPromoter

                                                                                                            @@ -415,10 +446,73 @@
                                                                                                            Property Value
                                                                                                            | - Improve this Doc + Improve this Doc + + + View Source + + +

                                                                                                            IsCaseSensitive

                                                                                                            +

                                                                                                            Gets or sets if parameter, method, and properties resolution should be case sensitive or not (false by default).

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            Declaration
                                                                                                            +
                                                                                                            +
                                                                                                            public bool IsCaseSensitive { get; set; }
                                                                                                            +
                                                                                                            +
                                                                                                            Property Value
                                                                                                            + + + + + + + + + + + + + +
                                                                                                            TypeDescription
                                                                                                            Boolean
                                                                                                            + + | + Improve this Doc + + + View Source + + +

                                                                                                            NullPropagatingUseDefaultValueForNonNullableValueTypes

                                                                                                            +

                                                                                                            When using the NullPropagating function np(...), use a "default value" for non-nullable value types instead of "null value".

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            Declaration
                                                                                                            +
                                                                                                            +
                                                                                                            public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; }
                                                                                                            +
                                                                                                            +
                                                                                                            Property Value
                                                                                                            + + + + + + + + + + + + + +
                                                                                                            TypeDescription
                                                                                                            Boolean
                                                                                                            + + | + Improve this Doc - View Source + View Source

                                                                                                            NumberParseCulture

                                                                                                            @@ -440,17 +534,50 @@
                                                                                                            Property Value
                                                                                                            - CultureInfo + CultureInfo | - Improve this Doc + Improve this Doc - View Source + View Source + + +

                                                                                                            PrioritizePropertyOrFieldOverTheType

                                                                                                            +

                                                                                                            When the type and property have the same name the parser takes the property instead of type when this setting is set to true.

                                                                                                            +

                                                                                                            This setting is also used for calling ExtensionMethods.

                                                                                                            +

                                                                                                            Default value is true.

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            Declaration
                                                                                                            +
                                                                                                            +
                                                                                                            public bool PrioritizePropertyOrFieldOverTheType { get; set; }
                                                                                                            +
                                                                                                            +
                                                                                                            Property Value
                                                                                                            + + + + + + + + + + + + + +
                                                                                                            TypeDescription
                                                                                                            Boolean
                                                                                                            + + | + Improve this Doc + + + View Source

                                                                                                            QueryableAnalyzer

                                                                                                            @@ -478,15 +605,47 @@
                                                                                                            Property Value
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source + + +

                                                                                                            RenameEmptyParameterExpressionNames

                                                                                                            +

                                                                                                            Prevents any System.Linq.Expressions.ParameterExpression.Name value from being empty by substituting a random 16 character word.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            Declaration
                                                                                                            +
                                                                                                            +
                                                                                                            public bool RenameEmptyParameterExpressionNames { get; set; }
                                                                                                            +
                                                                                                            +
                                                                                                            Property Value
                                                                                                            + + + + + + + + + + + + + +
                                                                                                            TypeDescription
                                                                                                            Boolean
                                                                                                            + + | + Improve this Doc + + + View Source

                                                                                                            RenameParameterExpression

                                                                                                            Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from it.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -503,24 +662,24 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            ResolveTypesBySimpleName

                                                                                                            By default finding types by a simple name is not supported. Use this flag to use the CustomTypeProvider to resolve types by a simple name like "Employee" instead of "MyDatabase.Entities.Employee". Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -537,17 +696,50 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean + + + + + + | + Improve this Doc + + + View Source + + +

                                                                                                            SupportCastingToFullyQualifiedTypeAsString

                                                                                                            +

                                                                                                            Support casting to a full qualified type using a string (double quoted value).

                                                                                                            +
                                                                                                            var result = queryable.Select($"\"System.DateTime\"(LastUpdate)");
                                                                                                            +

                                                                                                            Default value is true.

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            Declaration
                                                                                                            +
                                                                                                            +
                                                                                                            public bool SupportCastingToFullyQualifiedTypeAsString { get; set; }
                                                                                                            +
                                                                                                            +
                                                                                                            Property Value
                                                                                                            + + + + + + + + + +
                                                                                                            TypeDescription
                                                                                                            Boolean
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            SupportEnumerationsFromSystemNamespace

                                                                                                            @@ -569,27 +761,26 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean | - Improve this Doc + Improve this Doc - View Source + View Source - -

                                                                                                            UseDynamicObjectClassForAnonymousTypes

                                                                                                            -

                                                                                                            Gets or sets a value indicating whether to use dynamic object class for anonymous types.

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            + +

                                                                                                            TypeConverters

                                                                                                            +

                                                                                                            Additional TypeConverters

                                                                                                            Declaration
                                                                                                            -
                                                                                                            public bool UseDynamicObjectClassForAnonymousTypes { get; set; }
                                                                                                            +
                                                                                                            public IDictionary<Type, TypeConverter> TypeConverters { get; set; }
                                                                                                            Property Value
                                                                                                            @@ -601,23 +792,23 @@
                                                                                                            Property Value
                                                                                                            - +
                                                                                                            BooleanIDictionary<Type, TypeConverter>
                                                                                                            | - Improve this Doc + Improve this Doc - View Source + View Source

                                                                                                            UseParameterizedNamesInDynamicQuery

                                                                                                            Use Parameterized Names in generated dynamic SQL query. See https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd

                                                                                                            -

                                                                                                            Default value is false.

                                                                                                            +

                                                                                                            Default value is false.

                                                                                                            Declaration
                                                                                                            @@ -634,7 +825,7 @@
                                                                                                            Property Value
                                                                                                            - Boolean + Boolean @@ -647,15 +838,16 @@
                                                                                                            Property Value
                                                                                                            diff --git a/docs/api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html b/docs/api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html new file mode 100644 index 00000000..c2b1aa4d --- /dev/null +++ b/docs/api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html @@ -0,0 +1,328 @@ + + + + + + + + Class TextParser + + + + + + + + + + + + + + + + +
                                                                                                            +
                                                                                                            + + + + +
                                                                                                            +
                                                                                                            + +
                                                                                                            +
                                                                                                            Search Results for
                                                                                                            +
                                                                                                            +

                                                                                                            +
                                                                                                            +
                                                                                                              +
                                                                                                              +
                                                                                                              + + + +
                                                                                                              + + + + + + diff --git a/docs/api/System.Linq.Dynamic.Core.Tokenizer.Token.html b/docs/api/System.Linq.Dynamic.Core.Tokenizer.Token.html new file mode 100644 index 00000000..b81db55b --- /dev/null +++ b/docs/api/System.Linq.Dynamic.Core.Tokenizer.Token.html @@ -0,0 +1,284 @@ + + + + + + + + Struct Token + + + + + + + + + + + + + + + + +
                                                                                                              +
                                                                                                              + + + + +
                                                                                                              +
                                                                                                              + +
                                                                                                              +
                                                                                                              Search Results for
                                                                                                              +
                                                                                                              +

                                                                                                              +
                                                                                                              +
                                                                                                                +
                                                                                                                +
                                                                                                                + + + +
                                                                                                                + + + + + + diff --git a/docs/api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html b/docs/api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html new file mode 100644 index 00000000..1a45b514 --- /dev/null +++ b/docs/api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html @@ -0,0 +1,305 @@ + + + + + + + + Enum TokenId + + + + + + + + + + + + + + + + +
                                                                                                                +
                                                                                                                + + + + +
                                                                                                                +
                                                                                                                + +
                                                                                                                +
                                                                                                                Search Results for
                                                                                                                +
                                                                                                                +

                                                                                                                +
                                                                                                                +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  + + + +
                                                                                                                  + + + + + + diff --git a/docs/api/System.Linq.Dynamic.Core.Tokenizer.html b/docs/api/System.Linq.Dynamic.Core.Tokenizer.html new file mode 100644 index 00000000..dad26072 --- /dev/null +++ b/docs/api/System.Linq.Dynamic.Core.Tokenizer.html @@ -0,0 +1,139 @@ + + + + + + + + Namespace System.Linq.Dynamic.Core.Tokenizer + + + + + + + + + + + + + + + + +
                                                                                                                  +
                                                                                                                  + + + + +
                                                                                                                  +
                                                                                                                  + +
                                                                                                                  +
                                                                                                                  Search Results for
                                                                                                                  +
                                                                                                                  +

                                                                                                                  +
                                                                                                                  +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    + + + +
                                                                                                                    + + + + + + diff --git a/docs/api/System.Linq.Dynamic.Core.html b/docs/api/System.Linq.Dynamic.Core.html index 30fb9972..41e2e6f2 100644 --- a/docs/api/System.Linq.Dynamic.Core.html +++ b/docs/api/System.Linq.Dynamic.Core.html @@ -10,7 +10,7 @@ - + @@ -61,11 +61,11 @@
                                                                                                                    -
                                                                                                                    +
                                                                                                                    Search Results for

                                                                                                                    -
                                                                                                                      +
                                                                                                                        diff --git a/docs/api/System.Tuple-2.html b/docs/api/System.Tuple-2.html new file mode 100644 index 00000000..ad26279c --- /dev/null +++ b/docs/api/System.Tuple-2.html @@ -0,0 +1,251 @@ + + + + + + + + Class Tuple<T1, T2> + + + + + + + + + + + + + + + + +
                                                                                                                        +
                                                                                                                        + + + + +
                                                                                                                        +
                                                                                                                        + +
                                                                                                                        +
                                                                                                                        Search Results for
                                                                                                                        +
                                                                                                                        +

                                                                                                                        +
                                                                                                                        +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          + + + +
                                                                                                                          + + + + + + diff --git a/docs/api/System.html b/docs/api/System.html new file mode 100644 index 00000000..0b290949 --- /dev/null +++ b/docs/api/System.html @@ -0,0 +1,129 @@ + + + + + + + + Namespace System + + + + + + + + + + + + + + + + +
                                                                                                                          +
                                                                                                                          + + + + +
                                                                                                                          +
                                                                                                                          + +
                                                                                                                          +
                                                                                                                          Search Results for
                                                                                                                          +
                                                                                                                          +

                                                                                                                          +
                                                                                                                          +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            + + + +
                                                                                                                            + + + + + + diff --git a/docs/api/toc.html b/docs/api/toc.html index b64f00d5..4f222bf8 100644 --- a/docs/api/toc.html +++ b/docs/api/toc.html @@ -12,6 +12,16 @@
                                                                                                                          • @@ -109,6 +122,22 @@
                                                                                                                          • +
                                                                                                                          • + + System.Linq.Dynamic.Core.Tokenizer + + +
                                                                                                                          • diff --git a/docs/index.html b/docs/index.html index de189b89..d8d1d3e7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -8,7 +8,7 @@ System.Linq.Dynamic.Core - + @@ -59,11 +59,11 @@
                                                                                                                            -
                                                                                                                            +
                                                                                                                            Search Results for

                                                                                                                            -
                                                                                                                              +
                                                                                                                                diff --git a/docs/index.json b/docs/index.json index 48f80ea5..491bb727 100644 --- a/docs/index.json +++ b/docs/index.json @@ -1,93 +1,108 @@ { + "api/System.html": { + "href": "api/System.html", + "title": "Namespace System", + "keywords": "Namespace System Classes Tuple Represents a 2-tuple, or pair." + }, + "api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html": { + "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html", + "title": "Class AbstractDynamicLinqCustomTypeProvider", + "keywords": "Class AbstractDynamicLinqCustomTypeProvider The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. Inheritance Object AbstractDynamicLinqCustomTypeProvider DefaultDynamicLinqCustomTypeProvider Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public abstract class AbstractDynamicLinqCustomTypeProvider Methods | Improve this Doc View Source FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable) Finds the unique types marked with DynamicLinqTypeAttribute. Declaration protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to process. Returns Type Description IEnumerable < Type > IEnumerable | Improve this Doc View Source GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable) Gets the assembly types annotated with DynamicLinqTypeAttribute in an Exception friendly way. Declaration protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to process. Returns Type Description IEnumerable < Type > IEnumerable | Improve this Doc View Source ResolveType(IEnumerable, String) Resolve any type which is registered in the current application domain. Declaration protected Type ResolveType(IEnumerable assemblies, string typeName) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to inspect. String typeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found. | Improve this Doc View Source ResolveTypeBySimpleName(IEnumerable, String) Resolve a type by the simple name which is registered in the current application domain. Declaration protected Type ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to inspect. String simpleTypeName The simple typename to resolve. Returns Type Description Type A resolved Type or null when not found." + }, + "api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html": { + "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html", + "title": "Class DefaultDynamicLinqCustomTypeProvider", + "keywords": "Class DefaultDynamicLinqCustomTypeProvider The default implementation for DefaultDynamicLinqCustomTypeProvider . Scans the current AppDomain for all types marked with DynamicLinqTypeAttribute , and adds them as custom Dynamic Link types. Also provides functionality to resolve a Type in the current Application Domain. This class is used as default for full .NET Framework, so not for .NET Core Inheritance Object AbstractDynamicLinqCustomTypeProvider DefaultDynamicLinqCustomTypeProvider Implements IDynamicLinkCustomTypeProvider IDynamicLinqCustomTypeProvider Inherited Members AbstractDynamicLinqCustomTypeProvider.FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable) AbstractDynamicLinqCustomTypeProvider.ResolveType(IEnumerable, String) AbstractDynamicLinqCustomTypeProvider.ResolveTypeBySimpleName(IEnumerable, String) AbstractDynamicLinqCustomTypeProvider.GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable) Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider, IDynamicLinqCustomTypeProvider Constructors | Improve this Doc View Source DefaultDynamicLinqCustomTypeProvider(Boolean) Initializes a new instance of the DefaultDynamicLinqCustomTypeProvider class. Declaration public DefaultDynamicLinqCustomTypeProvider(bool cacheCustomTypes = true) Parameters Type Name Description Boolean cacheCustomTypes Defines whether to cache the CustomTypes (including extension methods) which are found in the Application Domain. Default set to 'true'. Methods | Improve this Doc View Source GetCustomTypes() Returns a list of custom types that System.Linq.Dynamic.Core will understand. Declaration public virtual HashSet GetCustomTypes() Returns Type Description HashSet < Type > A HashSet list of custom types. | Improve this Doc View Source GetExtensionMethods() Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand. Declaration public Dictionary> GetExtensionMethods() Returns Type Description Dictionary < Type , List < MethodInfo >> A list of custom extension methods that System.Linq.Dynamic.Core will understand. | Improve this Doc View Source ResolveType(String) Resolve any type by fullname which is registered in the current application domain. Declaration public Type ResolveType(string typeName) Parameters Type Name Description String typeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found. | Improve this Doc View Source ResolveTypeBySimpleName(String) Resolve any type by the simple name which is registered in the current application domain. Declaration public Type ResolveTypeBySimpleName(string simpleTypeName) Parameters Type Name Description String simpleTypeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found. Implements IDynamicLinkCustomTypeProvider IDynamicLinqCustomTypeProvider" + }, + "api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html": { + "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html", + "title": "Class DynamicLinqTypeAttribute", + "keywords": "Class DynamicLinqTypeAttribute Indicates to Dynamic Linq to consider the Type as a valid dynamic linq type. Inheritance Object Attribute DynamicLinqTypeAttribute Implements _Attribute Inherited Members Attribute.GetCustomAttributes(MemberInfo, Type) Attribute.GetCustomAttributes(MemberInfo, Type, Boolean) Attribute.GetCustomAttributes(MemberInfo) Attribute.GetCustomAttributes(MemberInfo, Boolean) Attribute.IsDefined(MemberInfo, Type) Attribute.IsDefined(MemberInfo, Type, Boolean) Attribute.GetCustomAttribute(MemberInfo, Type) Attribute.GetCustomAttribute(MemberInfo, Type, Boolean) Attribute.GetCustomAttributes(ParameterInfo) Attribute.GetCustomAttributes(ParameterInfo, Type) Attribute.GetCustomAttributes(ParameterInfo, Type, Boolean) Attribute.GetCustomAttributes(ParameterInfo, Boolean) Attribute.IsDefined(ParameterInfo, Type) Attribute.IsDefined(ParameterInfo, Type, Boolean) Attribute.GetCustomAttribute(ParameterInfo, Type) Attribute.GetCustomAttribute(ParameterInfo, Type, Boolean) Attribute.GetCustomAttributes(Module, Type) Attribute.GetCustomAttributes(Module) Attribute.GetCustomAttributes(Module, Boolean) Attribute.GetCustomAttributes(Module, Type, Boolean) Attribute.IsDefined(Module, Type) Attribute.IsDefined(Module, Type, Boolean) Attribute.GetCustomAttribute(Module, Type) Attribute.GetCustomAttribute(Module, Type, Boolean) Attribute.GetCustomAttributes(Assembly, Type) Attribute.GetCustomAttributes(Assembly, Type, Boolean) Attribute.GetCustomAttributes(Assembly) Attribute.GetCustomAttributes(Assembly, Boolean) Attribute.IsDefined(Assembly, Type) Attribute.IsDefined(Assembly, Type, Boolean) Attribute.GetCustomAttribute(Assembly, Type) Attribute.GetCustomAttribute(Assembly, Type, Boolean) Attribute.Equals(Object) Attribute.GetHashCode() Attribute.Match(Object) Attribute.IsDefaultAttribute() Attribute._Attribute.GetTypeInfoCount(UInt32) Attribute._Attribute.GetTypeInfo(UInt32, UInt32, IntPtr) Attribute._Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr) Attribute._Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr) Attribute.TypeId Object.ToString() Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] public sealed class DynamicLinqTypeAttribute : Attribute, _Attribute Implements System.Runtime.InteropServices._Attribute" + }, + "api/System.Linq.Dynamic.Core.CustomTypeProviders.html": { + "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.html", + "title": "Namespace System.Linq.Dynamic.Core.CustomTypeProviders", + "keywords": "Namespace System.Linq.Dynamic.Core.CustomTypeProviders Classes AbstractDynamicLinqCustomTypeProvider The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. DefaultDynamicLinqCustomTypeProvider The default implementation for DefaultDynamicLinqCustomTypeProvider . Scans the current AppDomain for all types marked with DynamicLinqTypeAttribute , and adds them as custom Dynamic Link types. Also provides functionality to resolve a Type in the current Application Domain. This class is used as default for full .NET Framework, so not for .NET Core DynamicLinqTypeAttribute Indicates to Dynamic Linq to consider the Type as a valid dynamic linq type. Interfaces IDynamicLinkCustomTypeProvider Interface for providing functionality to find custom types for or resolve any type. Note that this interface will be marked obsolete in the next version. Use IDynamicLinqCustomTypeProvider instead. IDynamicLinqCustomTypeProvider Interface for providing functionality to find custom types for or resolve any type." + }, "api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html": { "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html", "title": "Interface IDynamicLinkCustomTypeProvider", - "keywords": "Interface IDynamicLinkCustomTypeProvider Interface for providing functionality to find custom types for or resolve any type. Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IDynamicLinkCustomTypeProvider Methods | Improve this Doc View Source GetCustomTypes() Returns a list of custom types that System.Linq.Dynamic.Core will understand. Declaration HashSet GetCustomTypes() Returns Type Description HashSet < Type > A HashSet list of custom types. | Improve this Doc View Source ResolveType(String) Resolve any type by fullname which is registered in the current application domain. Declaration Type ResolveType([NotNull] string typeName) Parameters Type Name Description String typeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found. | Improve this Doc View Source ResolveTypeBySimpleName(String) Resolve any type by the simple name which is registered in the current application domain. Declaration Type ResolveTypeBySimpleName([NotNull] string simpleTypeName) Parameters Type Name Description String simpleTypeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found." - }, - "api/System.Linq.Dynamic.Core.IAssemblyHelper.html": { - "href": "api/System.Linq.Dynamic.Core.IAssemblyHelper.html", - "title": "Interface IAssemblyHelper", - "keywords": "Interface IAssemblyHelper IAssemblyHelper interface which is used to retrieve assemblies that have been loaded into the execution context of this application domain. Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IAssemblyHelper Methods | Improve this Doc View Source GetAssemblies() Gets the assemblies that have been loaded into the execution context of this application domain. Declaration Assembly[] GetAssemblies() Returns Type Description Assembly [] An array of assemblies in this application domain." + "keywords": "Interface IDynamicLinkCustomTypeProvider Interface for providing functionality to find custom types for or resolve any type. Note that this interface will be marked obsolete in the next version. Use IDynamicLinqCustomTypeProvider instead. Inherited Members IDynamicLinqCustomTypeProvider.GetCustomTypes() IDynamicLinqCustomTypeProvider.GetExtensionMethods() IDynamicLinqCustomTypeProvider.ResolveType(String) IDynamicLinqCustomTypeProvider.ResolveTypeBySimpleName(String) Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IDynamicLinkCustomTypeProvider : IDynamicLinqCustomTypeProvider" }, - "api/System.Linq.Dynamic.Core.Exceptions.html": { - "href": "api/System.Linq.Dynamic.Core.Exceptions.html", - "title": "Namespace System.Linq.Dynamic.Core.Exceptions", - "keywords": "Namespace System.Linq.Dynamic.Core.Exceptions Classes ParseException Represents errors that occur while parsing dynamic linq string expressions." + "api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html": { + "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html", + "title": "Interface IDynamicLinqCustomTypeProvider", + "keywords": "Interface IDynamicLinqCustomTypeProvider Interface for providing functionality to find custom types for or resolve any type. Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IDynamicLinqCustomTypeProvider Methods | Improve this Doc View Source GetCustomTypes() Returns a list of custom types that System.Linq.Dynamic.Core will understand. Declaration HashSet GetCustomTypes() Returns Type Description HashSet < Type > A HashSet list of custom types. | Improve this Doc View Source GetExtensionMethods() Returns a list of custom extension methods that System.Linq.Dynamic.Core will understand. Declaration Dictionary> GetExtensionMethods() Returns Type Description Dictionary < Type , List < MethodInfo >> A list of custom extension methods that System.Linq.Dynamic.Core will understand. | Improve this Doc View Source ResolveType(String) Resolve any type by fullname which is registered in the current application domain. Declaration Type ResolveType(string typeName) Parameters Type Name Description String typeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found. | Improve this Doc View Source ResolveTypeBySimpleName(String) Resolve any type by the simple name which is registered in the current application domain. Declaration Type ResolveTypeBySimpleName(string simpleTypeName) Parameters Type Name Description String simpleTypeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found." }, - "api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html": { - "href": "api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html", - "title": "Class DynamicQueryableExtensions", - "keywords": "Class DynamicQueryableExtensions Provides a set of static (Shared in Visual Basic) methods for querying data structures that implement IQueryable . It allows dynamic string based querying. Very handy when, at compile time, you don't know the type of queries that will be generated, or when downstream components only return column names to sort and filter by. Inheritance Object DynamicQueryableExtensions Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicQueryableExtensions Methods | Improve this Doc View Source Aggregate(IQueryable, String, String) Dynamically runs an aggregate function on the IQueryable. Declaration public static object Aggregate([NotNull] this IQueryable source, [NotNull] string function, [NotNull] string member) Parameters Type Name Description IQueryable source The IQueryable data source. String function The name of the function to run. Can be Sum, Average, Min or Max. String member The name of the property to aggregate over. Returns Type Description Object The value of the aggregate function run over the specified property. | Improve this Doc View Source All(IQueryable, ParsingConfig, String, Object[]) Determines whether all the elements of a sequence satisfy a condition. Declaration [PublicAPI] public static bool All([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source An IQueryable to calculate the All of. ParsingConfig config The ParsingConfig . String predicate A projection function to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Boolean true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. Remarks Multiple active operations on the same context instance are not supported. Use 'await' to ensure that All asynchronous operations have completed before calling another method on this context. | Improve this Doc View Source All(IQueryable, String, Object[]) Determines whether all the elements of a sequence satisfy a condition. Declaration [PublicAPI] public static bool All([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source An IQueryable to calculate the All of. String predicate A projection function to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Boolean true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. Remarks Multiple active operations on the same context instance are not supported. Use 'await' to ensure that All asynchronous operations have completed before calling another method on this context. | Improve this Doc View Source Any(IQueryable) Determines whether a sequence contains any elements. Declaration public static bool Any([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source A sequence to check for being empty. Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Any(); | Improve this Doc View Source Any(IQueryable, ParsingConfig, String, Object[]) Determines whether a sequence contains any elements. Declaration [PublicAPI] public static bool Any([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence to check for being empty. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Any(\"Income > 50\"); var result2 = queryable.Any(\"Income > @0\", 50); var result3 = queryable.Select(\"Roles.Any()\"); | Improve this Doc View Source Any(IQueryable, LambdaExpression) Determines whether a sequence contains any elements. Declaration public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence to check for being empty. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. | Improve this Doc View Source Any(IQueryable, String, Object[]) Declaration public static bool Any([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Boolean | Improve this Doc View Source AsEnumerable(IQueryable) Returns the input typed as IEnumerable of Object ./> Declaration public static IEnumerable AsEnumerable([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The sequence to type as IEnumerable of Object . Returns Type Description IEnumerable < Object > The input typed as IEnumerable of Object . | Improve this Doc View Source Average(IQueryable) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the average of. Returns Type Description Double The average of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Average(); var result2 = queryable.Select(\"Roles.Average()\"); | Improve this Doc View Source Average(IQueryable, ParsingConfig, String, Object[]) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the average of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Double The average of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Average(\"Income\"); | Improve this Doc View Source Average(IQueryable, LambdaExpression) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the average of. LambdaExpression lambda A Lambda Expression. Returns Type Description Double The average of the values in the sequence. | Improve this Doc View Source Average(IQueryable, String, Object[]) Declaration [PublicAPI] public static double Average([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Double | Improve this Doc View Source Cast(IQueryable, ParsingConfig, String) Converts the elements of an IQueryable to the specified type. Declaration public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be converted. ParsingConfig config The ParsingConfig . String typeName The type to convert the elements of source to. Returns Type Description IQueryable An IQueryable that contains each element of the source sequence converted to the specified type. | Improve this Doc View Source Cast(IQueryable, String) Converts the elements of an IQueryable to the specified type. Declaration public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] string typeName) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be converted. String typeName The type to convert the elements of source to. Returns Type Description IQueryable An IQueryable that contains each element of the source sequence converted to the specified type. | Improve this Doc View Source Cast(IQueryable, Type) Converts the elements of an IQueryable to the specified type. Declaration public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Type type) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be converted. Type type The type to convert the elements of source to. Returns Type Description IQueryable An IQueryable that contains each element of the source sequence converted to the specified type. | Improve this Doc View Source Count(IQueryable) Returns the number of elements in a sequence. Declaration public static int Count([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. Returns Type Description Int32 The number of elements in the input sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Count(); | Improve this Doc View Source Count(IQueryable, ParsingConfig, String, Object[]) Returns the number of elements in a sequence. Declaration [PublicAPI] public static int Count([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Int32 The number of elements in the specified sequence that satisfies a condition. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Count(\"Income > 50\"); var result2 = queryable.Count(\"Income > @0\", 50); var result3 = queryable.Select(\"Roles.Count()\"); | Improve this Doc View Source Count(IQueryable, LambdaExpression) Returns the number of elements in a sequence. Declaration public static int Count([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Int32 The number of elements in the specified sequence that satisfies a condition. | Improve this Doc View Source Count(IQueryable, String, Object[]) Declaration public static int Count([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Int32 | Improve this Doc View Source DefaultIfEmpty(IQueryable) Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty. Declaration public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return a default value for if empty. Returns Type Description IQueryable An IQueryable that contains default if source is empty; otherwise, source. Examples IQueryable queryable = employees.DefaultIfEmpty(); | Improve this Doc View Source DefaultIfEmpty(IQueryable, Object) Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty. Declaration public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source, [CanBeNull] object defaultValue) Parameters Type Name Description IQueryable source The IQueryable to return a default value for if empty. Object defaultValue The value to return if the sequence is empty. Returns Type Description IQueryable An IQueryable that contains defaultValue if source is empty; otherwise, source. Examples IQueryable queryable = employees.DefaultIfEmpty(new Employee()); | Improve this Doc View Source Distinct(IQueryable) Returns distinct elements from a sequence by using the default equality comparer to compare values. Declaration public static IQueryable Distinct([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The sequence to remove duplicate elements from. Returns Type Description IQueryable An IQueryable that contains distinct elements from the source sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Distinct(); var result2 = queryable.Select(\"Roles.Distinct()\"); | Improve this Doc View Source First(IQueryable) Returns the first element of a sequence. Declaration public static object First([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. Returns Type Description Object The first element in source. | Improve this Doc View Source First(IQueryable, ParsingConfig, String, Object[]) Returns the first element of a sequence that satisfies a specified condition. Declaration [PublicAPI] public static object First([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source First(IQueryable, LambdaExpression) Returns the first element of a sequence that satisfies a specified condition. Declaration public static object First([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source First(IQueryable, String, Object[]) Declaration public static object First([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source FirstOrDefault(IQueryable) Returns the first element of a sequence, or a default value if the sequence contains no elements. Declaration public static object FirstOrDefault([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. Returns Type Description Object default if source is empty; otherwise, the first element in source. | Improve this Doc View Source FirstOrDefault(IQueryable, ParsingConfig, String, Object[]) Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found. Declaration [PublicAPI] public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. | Improve this Doc View Source FirstOrDefault(IQueryable, LambdaExpression) Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found. Declaration public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. | Improve this Doc View Source FirstOrDefault(IQueryable, String, Object[]) Declaration public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration [PublicAPI] public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. Examples var groupResult1 = queryable.GroupBy(\"NumberPropertyAsKey\"); var groupResult2 = queryable.GroupBy(\"new (NumberPropertyAsKey, StringPropertyAsKey)\"); | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, String) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. String resultSelector A string expression to specify a result value from each group. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. Examples var groupResult1 = queryable.GroupBy(\"NumberPropertyAsKey\", \"StringProperty\"); var groupResult2 = queryable.GroupBy(\"new (NumberPropertyAsKey, StringPropertyAsKey)\", \"new (StringProperty1, StringProperty2)\"); | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, String, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration [PublicAPI] public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. String resultSelector A string expression to specify a result value from each group. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. Examples var groupResult1 = queryable.GroupBy(\"NumberPropertyAsKey\", \"StringProperty\"); var groupResult2 = queryable.GroupBy(\"new (NumberPropertyAsKey, StringPropertyAsKey)\", \"new (StringProperty1, StringProperty2)\"); | Improve this Doc View Source GroupBy(IQueryable, String, Object[]) Declaration [PublicAPI] public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source String keySelector Object [] args Returns Type Description IQueryable | Improve this Doc View Source GroupBy(IQueryable, String, String) Declaration public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector) Parameters Type Name Description IQueryable source String keySelector String resultSelector Returns Type Description IQueryable | Improve this Doc View Source GroupBy(IQueryable, String, String, Object[]) Declaration [PublicAPI] public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args) Parameters Type Name Description IQueryable source String keySelector String resultSelector Object [] args Returns Type Description IQueryable | Improve this Doc View Source GroupByMany(IEnumerable, Func[]) Groups the elements of a sequence according to multiple specified key functions and creates a result value from each group (and subgroups) and its key. Declaration public static IEnumerable GroupByMany([NotNull] this IEnumerable source, params Func[] keySelectors) Parameters Type Name Description IEnumerable source A IEnumerable whose elements to group. Func [] keySelectors Lambda expressions to specify the keys for each element. Returns Type Description IEnumerable < GroupResult > A IEnumerable of type GroupResult where each element represents a projection over a group, its key, and its subgroups. Type Parameters Name Description TElement | Improve this Doc View Source GroupByMany(IEnumerable, ParsingConfig, String[]) Groups the elements of a sequence according to multiple specified key string functions and creates a result value from each group (and subgroups) and its key. Declaration public static IEnumerable GroupByMany([NotNull] this IEnumerable source, [NotNull] ParsingConfig config, params string[] keySelectors) Parameters Type Name Description IEnumerable source A IEnumerable whose elements to group. ParsingConfig config The ParsingConfig . String [] keySelectors String expressions to specify the keys for each element. Returns Type Description IEnumerable < GroupResult > A IEnumerable of type GroupResult where each element represents a projection over a group, its key, and its subgroups. Type Parameters Name Description TElement | Improve this Doc View Source GroupByMany(IEnumerable, String[]) Declaration public static IEnumerable GroupByMany([NotNull] this IEnumerable source, params string[] keySelectors) Parameters Type Name Description IEnumerable source String [] keySelectors Returns Type Description IEnumerable < GroupResult > Type Parameters Name Description TElement | Improve this Doc View Source GroupJoin(IQueryable, IEnumerable, String, String, String, Object[]) Declaration public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer IEnumerable inner String outerKeySelector String innerKeySelector String resultSelector Object [] args Returns Type Description IQueryable | Improve this Doc View Source GroupJoin(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys. Declaration public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer The first sequence to join. ParsingConfig config The ParsingConfig . IEnumerable inner The sequence to join to the first sequence. String outerKeySelector A dynamic function to extract the join key from each element of the first sequence. String innerKeySelector A dynamic function to extract the join key from each element of the second sequence. String resultSelector A dynamic function to create a result element from an element from the first sequence and a collection of matching elements from the second sequence. Object [] args An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable obtained by performing a grouped join on two sequences. | Improve this Doc View Source Join(IQueryable, IEnumerable, String, String, String, Object[]) Declaration public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer IEnumerable inner String outerKeySelector String innerKeySelector String resultSelector Object [] args Returns Type Description IQueryable | Improve this Doc View Source Join(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. Declaration public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer The first sequence to join. ParsingConfig config The ParsingConfig . IEnumerable inner The sequence to join to the first sequence. String outerKeySelector A dynamic function to extract the join key from each element of the first sequence. String innerKeySelector A dynamic function to extract the join key from each element of the second sequence. String resultSelector A dynamic function to create a result element from two matching elements. Object [] args An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable obtained by performing an inner join on two sequences. | Improve this Doc View Source Join(IQueryable, IEnumerable, String, String, String, Object[]) Declaration public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer IEnumerable inner String outerKeySelector String innerKeySelector String resultSelector Object [] args Returns Type Description IQueryable Type Parameters Name Description TElement | Improve this Doc View Source Join(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. Declaration public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer The first sequence to join. ParsingConfig config The ParsingConfig . IEnumerable inner The sequence to join to the first sequence. String outerKeySelector A dynamic function to extract the join key from each element of the first sequence. String innerKeySelector A dynamic function to extract the join key from each element of the second sequence. String resultSelector A dynamic function to create a result element from two matching elements. Object [] args An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable that has elements of type TResult obtained by performing an inner join on two sequences. Type Parameters Name Description TElement The type of the elements of both sequences, and the result. Remarks This overload only works on elements where both sequences and the resulting element match. | Improve this Doc View Source Last(IQueryable) Returns the last element of a sequence. Declaration public static object Last([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. Returns Type Description Object The last element in source. | Improve this Doc View Source Last(IQueryable, ParsingConfig, String, Object[]) Returns the last element of a sequence that satisfies a specified condition. Declaration public static object Last([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Last(IQueryable, LambdaExpression) Returns the last element of a sequence that satisfies a specified condition. Declaration public static object Last([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Last(IQueryable, String, Object[]) Declaration public static object Last([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source LastOrDefault(IQueryable) Returns the last element of a sequence, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. Returns Type Description Object default if source is empty; otherwise, the last element in source. | Improve this Doc View Source LastOrDefault(IQueryable, ParsingConfig, String, Object[]) Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source LastOrDefault(IQueryable, LambdaExpression) Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source LastOrDefault(IQueryable, String, Object[]) Declaration public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source LongCount(IQueryable) Returns the number of elements in a sequence. Declaration public static long LongCount([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. Returns Type Description Int64 The number of elements in the input sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.LongCount(); | Improve this Doc View Source LongCount(IQueryable, ParsingConfig, String, Object[]) Returns the number of elements in a sequence. Declaration [PublicAPI] public static long LongCount([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Int64 The number of elements in the specified sequence that satisfies a condition. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.LongCount(\"Income > 50\"); var result2 = queryable.LongCount(\"Income > @0\", 50); var result3 = queryable.Select(\"Roles.LongCount()\"); | Improve this Doc View Source LongCount(IQueryable, LambdaExpression) Returns the number of elements in a sequence. Declaration public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Int64 The number of elements in the specified sequence that satisfies a condition. | Improve this Doc View Source LongCount(IQueryable, String, Object[]) Declaration public static long LongCount([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Int64 | Improve this Doc View Source OfType(IQueryable, ParsingConfig, String) Filters the elements of an IQueryable based on a specified type. Declaration public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName) Parameters Type Name Description IQueryable source An IQueryable whose elements to filter. ParsingConfig config The ParsingConfig . String typeName The type to filter the elements of the sequence on. Returns Type Description IQueryable A collection that contains the elements from source that have the type. | Improve this Doc View Source OfType(IQueryable, String) Filters the elements of an IQueryable based on a specified type. Declaration public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] string typeName) Parameters Type Name Description IQueryable source An IQueryable whose elements to filter. String typeName The type to filter the elements of the sequence on. Returns Type Description IQueryable A collection that contains the elements from source that have the type. | Improve this Doc View Source OfType(IQueryable, Type) Filters the elements of an IQueryable based on a specified type. Declaration public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Type type) Parameters Type Name Description IQueryable source An IQueryable whose elements to filter. Type type The type to filter the elements of the sequence on. Returns Type Description IQueryable A collection that contains the elements from source that have the type. | Improve this Doc View Source OrderBy(IQueryable, ParsingConfig, String, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Examples var resultSingle = queryable.OrderBy(\"NumberProperty\"); var resultSingleDescending = queryable.OrderBy(\"NumberProperty DESC\"); var resultMultiple = queryable.OrderBy(\"NumberProperty, StringProperty DESC\"); | Improve this Doc View Source OrderBy(IQueryable, String, Object[]) Declaration public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args) Parameters Type Name Description IQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable | Improve this Doc View Source OrderBy(IQueryable, ParsingConfig, String, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. Examples var resultSingle = queryable.OrderBy(\"NumberProperty\"); var resultSingleDescending = queryable.OrderBy(\"NumberProperty DESC\"); var resultMultiple = queryable.OrderBy(\"NumberProperty, StringProperty\"); | Improve this Doc View Source OrderBy(IQueryable, String, Object[]) Declaration public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args) Parameters Type Name Description IQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable Type Parameters Name Description TSource | Improve this Doc View Source Page(IQueryable, Int32, Int32) Returns the elements as paged. Declaration public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Returns Type Description IQueryable A IQueryable that contains the paged elements. | Improve this Doc View Source Page(IQueryable, Int32, Int32) Returns the elements as paged. Declaration public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Returns Type Description IQueryable A IQueryable that contains the paged elements. Type Parameters Name Description TSource The type of the source. | Improve this Doc View Source PageResult(IQueryable, Int32, Int32) Returns the elements as paged and include the CurrentPage, PageCount, PageSize and RowCount. Declaration public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Returns Type Description PagedResult PagedResult | Improve this Doc View Source PageResult(IQueryable, Int32, Int32) Returns the elements as paged and include the CurrentPage, PageCount, PageSize and RowCount. Declaration public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Returns Type Description PagedResult PagedResult{TSource} Type Parameters Name Description TSource The type of the source. | Improve this Doc View Source Reverse(IQueryable) Inverts the order of the elements in a sequence. Declaration public static IQueryable Reverse([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source A sequence of values to reverse. Returns Type Description IQueryable A IQueryable whose elements correspond to those of the input sequence in reverse order. | Improve this Doc View Source Select(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence into a new form. Declaration public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Examples var singleField = queryable.Select(\"StringProperty\"); var dynamicObject = queryable.Select(\"new (StringProperty1, StringProperty2 as OtherStringPropertyName)\"); | Improve this Doc View Source Select(IQueryable, ParsingConfig, Type, String, Object[]) Projects each element of a sequence into a new class of type TResult. Details see http://solutionizing.net/category/linq/ Declaration public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . Type resultType The result type. String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Examples var users = queryable.Select(typeof(User), \"new (Username, Pwd as Password)\"); | Improve this Doc View Source Select(IQueryable, String, Object[]) Declaration public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable | Improve this Doc View Source Select(IQueryable, Type, String, Object[]) Declaration public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source Type resultType String selector Object [] args Returns Type Description IQueryable | Improve this Doc View Source Select(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence into a new class of type TResult. Details see http://solutionizing.net/category/linq/ . Declaration public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Type Parameters Name Description TResult The type of the result. Examples var users = queryable.Select(\"new (Username, Pwd as Password)\"); | Improve this Doc View Source Select(IQueryable, String, Object[]) Declaration public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable Type Parameters Name Description TResult | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Examples var roles = users.SelectMany(\"Roles\"); | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, String, Object[], Object[]) Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned. Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String collectionSelector A projection function to apply to each element of the input sequence. String resultSelector A projection function to apply to each element of each intermediate sequence. Should only use x and y as parameter names. Object [] collectionSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Object [] resultSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element. Examples // TODO | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, String, String, String, Object[], Object[]) Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned. Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String collectionSelector A projection function to apply to each element of the input sequence. String resultSelector A projection function to apply to each element of each intermediate sequence. String collectionParameterName The name from collectionParameter to use. Default is x. String resultParameterName The name from resultParameterName to use. Default is y. Object [] collectionSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Object [] resultSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element. Examples // TODO | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, Type, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . Type resultType The result type. String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Examples var permissions = users.SelectMany(typeof(Permission), \"Roles.SelectMany(Permissions)\"); | Improve this Doc View Source SelectMany(IQueryable, String, Object[]) Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable | Improve this Doc View Source SelectMany(IQueryable, String, String, Object[], Object[]) Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source String collectionSelector String resultSelector Object [] collectionSelectorArgs Object [] resultSelectorArgs Returns Type Description IQueryable | Improve this Doc View Source SelectMany(IQueryable, String, String, String, String, Object[], Object[]) Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source String collectionSelector String resultSelector String collectionParameterName String resultParameterName Object [] collectionSelectorArgs Object [] resultSelectorArgs Returns Type Description IQueryable | Improve this Doc View Source SelectMany(IQueryable, Type, String, Object[]) Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source Type resultType String selector Object [] args Returns Type Description IQueryable | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Type Parameters Name Description TResult The type of the result. Examples var permissions = users.SelectMany(\"Roles.SelectMany(Permissions)\"); | Improve this Doc View Source SelectMany(IQueryable, String, Object[]) Declaration public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable Type Parameters Name Description TResult | Improve this Doc View Source Single(IQueryable) Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source A IQueryable to return the single element of. Returns Type Description Object The single element of the input sequence. | Improve this Doc View Source Single(IQueryable, ParsingConfig, String, Object[]) Returns the only element of a sequence that satisfies a specified condition, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Single(IQueryable, LambdaExpression) Returns the only element of a sequence that satisfies a specified condition, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Single(IQueryable, String, Object[]) Declaration public static object Single([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source SingleOrDefault(IQueryable) Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence. Declaration public static object SingleOrDefault([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source A IQueryable to return the single element of. Returns Type Description Object The single element of the input sequence, or default if the sequence contains no elements. | Improve this Doc View Source SingleOrDefault(IQueryable, ParsingConfig, String, Object[]) Returns the only element of a sequence that satisfies a specified condition or a default value if the sequence is empty; and throws an exception if there is not exactly one element in the sequence. Declaration public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source SingleOrDefault(IQueryable, LambdaExpression) Returns the only element of a sequence that satisfies a specified condition or a default value if the sequence is empty; and throws an exception if there is not exactly one element in the sequence. Declaration public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source SingleOrDefault(IQueryable, String, Object[]) Declaration public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source Skip(IQueryable, Int32) Bypasses a specified number of elements in a sequence and then returns the remaining elements. Declaration public static IQueryable Skip([NotNull] this IQueryable source, int count) Parameters Type Name Description IQueryable source A IQueryable to return elements from. Int32 count The number of elements to skip before returning the remaining elements. Returns Type Description IQueryable A IQueryable that contains elements that occur after the specified index in the input sequence. | Improve this Doc View Source SkipWhile(IQueryable, ParsingConfig, String, Object[]) Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. Declaration public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source A sequence to check for being empty. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.SkipWhile(\"Income > 50\"); var result2 = queryable.SkipWhile(\"Income > @0\", 50); | Improve this Doc View Source SkipWhile(IQueryable, String, Object[]) Declaration public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable | Improve this Doc View Source Sum(IQueryable) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum([NotNull] this IQueryable source) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the sum of. Returns Type Description Object The sum of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Sum(); var result2 = queryable.Select(\"Roles.Sum()\"); | Improve this Doc View Source Sum(IQueryable, ParsingConfig, String, Object[]) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the sum of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The sum of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Sum(\"Income\"); | Improve this Doc View Source Sum(IQueryable, LambdaExpression) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the sum of. LambdaExpression lambda A Lambda Expression. Returns Type Description Object The sum of the values in the sequence. | Improve this Doc View Source Sum(IQueryable, String, Object[]) Declaration [PublicAPI] public static object Sum([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object | Improve this Doc View Source Take(IQueryable, Int32) Returns a specified number of contiguous elements from the start of a sequence. Declaration public static IQueryable Take([NotNull] this IQueryable source, int count) Parameters Type Name Description IQueryable source The sequence to return elements from. Int32 count The number of elements to return. Returns Type Description IQueryable A IQueryable that contains the specified number of elements from the start of source. | Improve this Doc View Source TakeWhile(IQueryable, ParsingConfig, String, Object[]) Returns elements from a sequence as long as a specified condition is true. Declaration public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source A sequence to check for being empty. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.TakeWhile(\"Income > 50\"); var result2 = queryable.TakeWhile(\"Income > @0\", 50); | Improve this Doc View Source TakeWhile(IQueryable, String, Object[]) Declaration public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable | Improve this Doc View Source ThenBy(IOrderedQueryable, ParsingConfig, String, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Examples var result = queryable.OrderBy(\"LastName\"); var resultSingle = result.OrderBy(\"NumberProperty\"); var resultSingleDescending = result.OrderBy(\"NumberProperty DESC\"); var resultMultiple = result.OrderBy(\"NumberProperty, StringProperty DESC\"); | Improve this Doc View Source ThenBy(IOrderedQueryable, String, Object[]) Declaration public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable | Improve this Doc View Source ThenBy(IOrderedQueryable, ParsingConfig, String, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IOrderedQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. Examples var result = queryable.OrderBy(\"LastName\"); var resultSingle = result.ThenBy(\"NumberProperty\"); var resultSingleDescending = result.ThenBy(\"NumberProperty DESC\"); var resultMultiple = result.ThenBy(\"NumberProperty, StringProperty\"); | Improve this Doc View Source ThenBy(IOrderedQueryable, String, Object[]) Declaration public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable Type Parameters Name Description TSource | Improve this Doc View Source Where(IQueryable, ParsingConfig, String, Object[]) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source A IQueryable to filter. ParsingConfig config The ParsingConfig . String predicate An expression string to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate. Examples var result1 = queryable.Where(\"NumberProperty = 1\"); var result2 = queryable.Where(\"NumberProperty = @0\", 1); var result3 = queryable.Where(\"StringProperty = null\"); var result4 = queryable.Where(\"StringProperty = \\\"abc\\\"\"); var result5 = queryable.Where(\"StringProperty = @0\", \"abc\"); | Improve this Doc View Source Where(IQueryable, LambdaExpression) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) Parameters Type Name Description IQueryable source A IQueryable to filter. LambdaExpression lambda A cached Lambda Expression. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by LambdaExpression. | Improve this Doc View Source Where(IQueryable, String, Object[]) Declaration public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable | Improve this Doc View Source Where(IQueryable, ParsingConfig, String, Object[]) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source A IQueryable to filter. ParsingConfig config The ParsingConfig . String predicate An expression string to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate. Type Parameters Name Description TSource The type of the elements of source. Examples var result1 = queryable.Where(\"NumberProperty = 1\"); var result2 = queryable.Where(\"NumberProperty = @0\", 1); var result3 = queryable.Where(\"StringProperty = null\"); var result4 = queryable.Where(\"StringProperty = \\\"abc\\\"\"); var result5 = queryable.Where(\"StringProperty = @0\", \"abc\"); | Improve this Doc View Source Where(IQueryable, String, Object[]) Declaration public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable Type Parameters Name Description TSource" - }, - "api/System.Linq.Dynamic.Core.DynamicExpressionParser.html": { - "href": "api/System.Linq.Dynamic.Core.DynamicExpressionParser.html", - "title": "Class DynamicExpressionParser", - "keywords": "Class DynamicExpressionParser Helper class to convert an expression into an LambdaExpression Inheritance Object DynamicExpressionParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicExpressionParser Methods | Improve this Doc View Source ParseLambda(Boolean, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) Parameters Type Name Description Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Boolean, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) Parameters Type Name Description Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) Parameters Type Name Description ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull] string expression, params object[] values) Parameters Type Name Description Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) Parameters Type Name Description Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, ParameterExpression[], String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [NotNull] string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description T The it -Type. TResult The type of the result." + "api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html": { + "href": "api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html", + "title": "Class DefaultQueryableAnalyzer", + "keywords": "Class DefaultQueryableAnalyzer Default implementation. Inheritance Object DefaultQueryableAnalyzer Implements IQueryableAnalyzer Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class DefaultQueryableAnalyzer : IQueryableAnalyzer Methods | Improve this Doc View Source SupportsLinqToObjects(IQueryable, IQueryProvider) Determines whether the specified query (and provider) supports LinqToObjects. Declaration public bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null) Parameters Type Name Description IQueryable query The query to check. IQueryProvider provider The provider to check (can be null). Returns Type Description Boolean true/false Implements IQueryableAnalyzer See Also IQueryableAnalyzer" }, "api/System.Linq.Dynamic.Core.DynamicClass.html": { "href": "api/System.Linq.Dynamic.Core.DynamicClass.html", "title": "Class DynamicClass", "keywords": "Class DynamicClass Provides a base class for dynamic objects for Net 3.5 Inheritance Object DynamicClass Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public abstract class DynamicClass Methods | Improve this Doc View Source GetDynamicPropertyValue(String) Gets the dynamic property value by name. Declaration public object GetDynamicPropertyValue(string propertyName) Parameters Type Name Description String propertyName Name of the property. Returns Type Description Object value | Improve this Doc View Source GetDynamicPropertyValue(String) Gets the dynamic property by name. Declaration public T GetDynamicPropertyValue(string propertyName) Parameters Type Name Description String propertyName Name of the property. Returns Type Description T T Type Parameters Name Description T The type. | Improve this Doc View Source SetDynamicPropertyValue(String, Object) Sets the dynamic property value by name. Declaration public void SetDynamicPropertyValue(string propertyName, object value) Parameters Type Name Description String propertyName Name of the property. Object value The value. | Improve this Doc View Source SetDynamicPropertyValue(String, T) Sets the dynamic property value by name. Declaration public void SetDynamicPropertyValue(string propertyName, T value) Parameters Type Name Description String propertyName Name of the property. T value The value. Type Parameters Name Description T The type." }, - "api/System.Linq.Dynamic.Core.CustomTypeProviders.html": { - "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.html", - "title": "Namespace System.Linq.Dynamic.Core.CustomTypeProviders", - "keywords": "Namespace System.Linq.Dynamic.Core.CustomTypeProviders Classes AbstractDynamicLinqCustomTypeProvider The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. DefaultDynamicLinqCustomTypeProvider The default implementation for IDynamicLinkCustomTypeProvider . Scans the current AppDomain for all types marked with DynamicLinqTypeAttribute , and adds them as custom Dynamic Link types. Also provides functionality to resolve a Type in the current Application Domain. This class is used as default for full .NET Framework, so not for .NET Core DynamicLinqTypeAttribute Indicates to Dynamic Linq to consider the Type as a valid dynamic linq type. Interfaces IDynamicLinkCustomTypeProvider Interface for providing functionality to find custom types for or resolve any type." + "api/System.Linq.Dynamic.Core.DynamicClassFactory.html": { + "href": "api/System.Linq.Dynamic.Core.DynamicClassFactory.html", + "title": "Class DynamicClassFactory", + "keywords": "Class DynamicClassFactory A factory to create dynamic classes, based on http://stackoverflow.com/questions/29413942/c-sharp-anonymous-object-with-properties-from-dictionary . Inheritance Object DynamicClassFactory Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicClassFactory Methods | Improve this Doc View Source CreateGenericComparerType(Type, Type) Create a GenericComparerType based on the GenericType and an instance of a IComparer . Declaration public static Type CreateGenericComparerType(Type comparerGenericType, Type comparerType) Parameters Type Name Description Type comparerGenericType The GenericType Type comparerType The IComparer instance Returns Type Description Type Type | Improve this Doc View Source CreateType(IList, Boolean) The CreateType method creates a new data class with a given set of public properties and returns the System.Type object for the newly created class. If a data class with an identical sequence of properties has already been created, the System.Type object for this class is returned. Data classes implement private instance variables and read/write property accessors for the specified properties.Data classes also override the Equals and GetHashCode members to implement by-value equality. Data classes are created in an in-memory assembly in the current application domain. All data classes inherit from DynamicClass and are given automatically generated names that should be considered private (the names will be unique within the application domain but not across multiple invocations of the application). Note that once created, a data class stays in memory for the lifetime of the current application domain. There is currently no way to unload a dynamically created data class. The dynamic expression parser uses the CreateClass methods to generate classes from data object initializers. This feature in turn is often used with the dynamic Select method to create projections. Declaration public static Type CreateType(IList properties, bool createParameterCtor = true) Parameters Type Name Description IList < DynamicProperty > properties The DynamicProperties Boolean createParameterCtor Create a constructor with parameters. Default set to true. Note that for Linq-to-Database objects, this needs to be set to false. Returns Type Description Type Type Examples DynamicProperty[] props = new DynamicProperty[] { new DynamicProperty(\"Name\", typeof(string)), new DynamicProperty(\"Birthday\", typeof(DateTime)) }; Type type = DynamicClassFactory.CreateType(props); DynamicClass dynamicClass = Activator.CreateInstance(type) as DynamicClass; dynamicClass.SetDynamicProperty(\"Name\", \"Albert\"); dynamicClass.SetDynamicProperty(\"Birthday\", new DateTime(1879, 3, 14)); Console.WriteLine(dynamicClass);" }, - "api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html": { - "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html", - "title": "Class DefaultDynamicLinqCustomTypeProvider", - "keywords": "Class DefaultDynamicLinqCustomTypeProvider The default implementation for IDynamicLinkCustomTypeProvider . Scans the current AppDomain for all types marked with DynamicLinqTypeAttribute , and adds them as custom Dynamic Link types. Also provides functionality to resolve a Type in the current Application Domain. This class is used as default for full .NET Framework, so not for .NET Core Inheritance Object AbstractDynamicLinqCustomTypeProvider DefaultDynamicLinqCustomTypeProvider Implements IDynamicLinkCustomTypeProvider Inherited Members AbstractDynamicLinqCustomTypeProvider.FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable) AbstractDynamicLinqCustomTypeProvider.ResolveType(IEnumerable, String) AbstractDynamicLinqCustomTypeProvider.ResolveTypeBySimpleName(IEnumerable, String) AbstractDynamicLinqCustomTypeProvider.GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable) Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider Constructors | Improve this Doc View Source DefaultDynamicLinqCustomTypeProvider(Boolean) Initializes a new instance of the DefaultDynamicLinqCustomTypeProvider class. Declaration public DefaultDynamicLinqCustomTypeProvider(bool cacheCustomTypes = true) Parameters Type Name Description Boolean cacheCustomTypes Defines whether to cache the CustomTypes which are found in the Application Domain. Default set to 'true'. Methods | Improve this Doc View Source GetCustomTypes() Declaration public virtual HashSet GetCustomTypes() Returns Type Description HashSet < Type > | Improve this Doc View Source ResolveType(String) Declaration public Type ResolveType(string typeName) Parameters Type Name Description String typeName Returns Type Description Type | Improve this Doc View Source ResolveTypeBySimpleName(String) Declaration public Type ResolveTypeBySimpleName(string simpleTypeName) Parameters Type Name Description String simpleTypeName Returns Type Description Type Implements IDynamicLinkCustomTypeProvider" + "api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html": { + "href": "api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html", + "title": "Class DynamicEnumerableExtensions", + "keywords": "Class DynamicEnumerableExtensions Define extensions on IEnumerable . Inheritance Object DynamicEnumerableExtensions Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicEnumerableExtensions Methods | Improve this Doc View Source ToDynamicArray(IEnumerable) Creates an array of dynamic objects from a IEnumerable . Declaration public static object[] ToDynamicArray(this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description Object [] An array that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicArray(IEnumerable, Type) Creates an array of dynamic objects from a IEnumerable . Declaration public static object[] ToDynamicArray(this IEnumerable source, Type type) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Type type A Type cast to. Returns Type Description Object [] An Array that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicArray(IEnumerable) Creates an array of dynamic objects from a IEnumerable . Declaration public static T[] ToDynamicArray(this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description T[] An Array{T} that contains the elements from the input sequence. Type Parameters Name Description T The generic type. | Improve this Doc View Source ToDynamicList(IEnumerable) Creates a list of dynamic objects from a IEnumerable . Declaration public static List ToDynamicList(this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description List < Object > A List that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicList(IEnumerable, Type) Creates a list of dynamic objects from a IEnumerable . Declaration public static List ToDynamicList(this IEnumerable source, Type type) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Type type A Type cast to. Returns Type Description List < Object > A List that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicList(IEnumerable) Creates a list of dynamic objects from a IEnumerable . Declaration public static List ToDynamicList(this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description List A List{T} that contains the elements from the input sequence. Type Parameters Name Description T Generic Type" }, - "api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html": { - "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html", - "title": "Class DynamicLinqTypeAttribute", - "keywords": "Class DynamicLinqTypeAttribute Indicates to Dynamic Linq to consider the Type as a valid dynamic linq type. Inheritance Object Attribute DynamicLinqTypeAttribute Implements _Attribute Inherited Members Attribute.GetCustomAttributes(MemberInfo, Type) Attribute.GetCustomAttributes(MemberInfo, Type, Boolean) Attribute.GetCustomAttributes(MemberInfo) Attribute.GetCustomAttributes(MemberInfo, Boolean) Attribute.IsDefined(MemberInfo, Type) Attribute.IsDefined(MemberInfo, Type, Boolean) Attribute.GetCustomAttribute(MemberInfo, Type) Attribute.GetCustomAttribute(MemberInfo, Type, Boolean) Attribute.GetCustomAttributes(ParameterInfo) Attribute.GetCustomAttributes(ParameterInfo, Type) Attribute.GetCustomAttributes(ParameterInfo, Type, Boolean) Attribute.GetCustomAttributes(ParameterInfo, Boolean) Attribute.IsDefined(ParameterInfo, Type) Attribute.IsDefined(ParameterInfo, Type, Boolean) Attribute.GetCustomAttribute(ParameterInfo, Type) Attribute.GetCustomAttribute(ParameterInfo, Type, Boolean) Attribute.GetCustomAttributes(Module, Type) Attribute.GetCustomAttributes(Module) Attribute.GetCustomAttributes(Module, Boolean) Attribute.GetCustomAttributes(Module, Type, Boolean) Attribute.IsDefined(Module, Type) Attribute.IsDefined(Module, Type, Boolean) Attribute.GetCustomAttribute(Module, Type) Attribute.GetCustomAttribute(Module, Type, Boolean) Attribute.GetCustomAttributes(Assembly, Type) Attribute.GetCustomAttributes(Assembly, Type, Boolean) Attribute.GetCustomAttributes(Assembly) Attribute.GetCustomAttributes(Assembly, Boolean) Attribute.IsDefined(Assembly, Type) Attribute.IsDefined(Assembly, Type, Boolean) Attribute.GetCustomAttribute(Assembly, Type) Attribute.GetCustomAttribute(Assembly, Type, Boolean) Attribute.Equals(Object) Attribute.GetHashCode() Attribute.Match(Object) Attribute.IsDefaultAttribute() Attribute._Attribute.GetTypeInfoCount(UInt32) Attribute._Attribute.GetTypeInfo(UInt32, UInt32, IntPtr) Attribute._Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr) Attribute._Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr) Attribute.TypeId Object.ToString() Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] public sealed class DynamicLinqTypeAttribute : Attribute, _Attribute Implements System.Runtime.InteropServices._Attribute" + "api/System.Linq.Dynamic.Core.DynamicExpressionParser.html": { + "href": "api/System.Linq.Dynamic.Core.DynamicExpressionParser.html", + "title": "Class DynamicExpressionParser", + "keywords": "Class DynamicExpressionParser Helper class to convert an expression into an LambdaExpression Inheritance Object DynamicExpressionParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicExpressionParser Methods | Improve this Doc View Source ParseLambda(Boolean, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Boolean, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type resultType, string expression, params object[] values) Parameters Type Name Description Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, Type itType, Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParsingConfig parsingConfig, Type itType, Type resultType, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Boolean, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Boolean, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Boolean, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, Type itType, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParsingConfig, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Type, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig parsingConfig, Type itType, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, ParameterExpression[], Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type resultType, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParameterExpression [] parameters A array from ParameterExpressions. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type resultType, string expression, params object[] values) Parameters Type Name Description Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(Type, Type, String, Object[]) Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.) Declaration [PublicAPI] public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values) Parameters Type Name Description Type itType The main type from the dynamic class expression. Type resultType Type of the result. If not specified, it will be generated dynamically. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description LambdaExpression The generated LambdaExpression | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, ParameterExpression[], String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Boolean, ParameterExpression[], String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. ParameterExpression [] parameters A array from ParameterExpressions. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Boolean, String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source ParseLambda(ParsingConfig, Boolean, String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda(ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values) Parameters Type Name Description ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description T The it -Type. TResult The type of the result. | Improve this Doc View Source ParseLambda(Type, ParsingConfig, Boolean, String, Object[]) Parses an expression into a Typed Expression. Declaration [PublicAPI] public static Expression> ParseLambda(Type delegateType, ParsingConfig parsingConfig, bool createParameterCtor, string expression, params object[] values) Parameters Type Name Description Type delegateType The delegate type. ParsingConfig parsingConfig The Configuration for the parsing. Boolean createParameterCtor if set to true then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities. String expression The expression. Object [] values An object array that contains zero or more objects which are used as replacement values. Returns Type Description Expression < Func > The generated Expression Type Parameters Name Description T The it -Type. TResult The type of the result." }, - "api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html": { - "href": "api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html", - "title": "Class AbstractDynamicLinqCustomTypeProvider", - "keywords": "Class AbstractDynamicLinqCustomTypeProvider The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. Inheritance Object AbstractDynamicLinqCustomTypeProvider DefaultDynamicLinqCustomTypeProvider Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.CustomTypeProviders Assembly : System.Linq.Dynamic.Core.dll Syntax public abstract class AbstractDynamicLinqCustomTypeProvider Methods | Improve this Doc View Source FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable) Finds the unique types marked with DynamicLinqTypeAttribute. Declaration protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to process. Returns Type Description IEnumerable < Type > IEnumerable | Improve this Doc View Source GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable) Gets the assembly types annotated with DynamicLinqTypeAttribute in an Exception friendly way. Declaration protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to process. Returns Type Description IEnumerable < Type > IEnumerable | Improve this Doc View Source ResolveType(IEnumerable, String) Resolve any type which is registered in the current application domain. Declaration protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull] string typeName) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to inspect. String typeName The typename to resolve. Returns Type Description Type A resolved Type or null when not found. | Improve this Doc View Source ResolveTypeBySimpleName(IEnumerable, String) Resolve a type by the simple name which is registered in the current application domain. Declaration protected Type ResolveTypeBySimpleName([NotNull] IEnumerable assemblies, [NotNull] string simpleTypeName) Parameters Type Name Description IEnumerable < Assembly > assemblies The assemblies to inspect. String simpleTypeName The simple typename to resolve. Returns Type Description Type A resolved Type or null when not found." + "api/System.Linq.Dynamic.Core.DynamicProperty.html": { + "href": "api/System.Linq.Dynamic.Core.DynamicProperty.html", + "title": "Class DynamicProperty", + "keywords": "Class DynamicProperty DynamicProperty Inheritance Object DynamicProperty Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class DynamicProperty Constructors | Improve this Doc View Source DynamicProperty(String, Type) Initializes a new instance of the DynamicProperty class. Declaration public DynamicProperty(string name, Type type) Parameters Type Name Description String name The name from the property. Type type The type from the property. Properties | Improve this Doc View Source Name Gets the name from the property. Declaration public string Name { get; } Property Value Type Description String The name from the property. | Improve this Doc View Source Type Gets the type from the property. Declaration public Type Type { get; } Property Value Type Description Type The type from the property." }, - "api/System.Linq.Dynamic.Core.ParsingConfig.html": { - "href": "api/System.Linq.Dynamic.Core.ParsingConfig.html", - "title": "Class ParsingConfig", - "keywords": "Class ParsingConfig Configuration class for System.Linq.Dynamic.Core. Inheritance Object ParsingConfig Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class ParsingConfig Properties | Improve this Doc View Source AllowNewToEvaluateAnyType Allows the New() keyword to evaluate any available Type. Default value is false. Declaration public bool AllowNewToEvaluateAnyType { get; set; } Property Value Type Description Boolean | Improve this Doc View Source AreContextKeywordsEnabled Determines if the context keywords (it, parent, and root) are valid and usable inside a Dynamic Linq string expression. Does not affect the usability of the equivalent context symbols ($, ^ and ~). Default value is true. Declaration public bool AreContextKeywordsEnabled { get; set; } Property Value Type Description Boolean | Improve this Doc View Source CustomTypeProvider Gets or sets the IDynamicLinkCustomTypeProvider . Declaration public IDynamicLinkCustomTypeProvider CustomTypeProvider { get; set; } Property Value Type Description IDynamicLinkCustomTypeProvider | Improve this Doc View Source DateTimeIsParsedAsUTC By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. Use this flag to parse all DateTime strings as UTC. Default value is false. Declaration public bool DateTimeIsParsedAsUTC { get; set; } Property Value Type Description Boolean | Improve this Doc View Source Default Default ParsingConfig Declaration public static ParsingConfig Default { get; } Property Value Type Description ParsingConfig | Improve this Doc View Source DefaultEFCore21 Default ParsingConfig for EntityFramework Core 2.1 and higher Declaration public static ParsingConfig DefaultEFCore21 { get; } Property Value Type Description ParsingConfig | Improve this Doc View Source DisableMemberAccessToIndexAccessorFallback By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use this flag to disable this behaviour and have parsing fail when parsing an expression where a member access on a non existing member happens. Default value is false. Declaration public bool DisableMemberAccessToIndexAccessorFallback { get; set; } Property Value Type Description Boolean | Improve this Doc View Source EvaluateGroupByAtDatabase Gets or sets a value indicating whether the EntityFramework version supports evaluating GroupBy at database level. See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods. Default value is false. Declaration public bool EvaluateGroupByAtDatabase { get; set; } Property Value Type Description Boolean | Improve this Doc View Source ExpressionPromoter Gets or sets the IExpressionPromoter . Declaration public IExpressionPromoter ExpressionPromoter { get; set; } Property Value Type Description IExpressionPromoter | Improve this Doc View Source NumberParseCulture The number parsing culture. Default value is CultureInfo.InvariantCulture Declaration public CultureInfo NumberParseCulture { get; set; } Property Value Type Description CultureInfo | Improve this Doc View Source QueryableAnalyzer Gets or sets the IQueryableAnalyzer . Declaration public IQueryableAnalyzer QueryableAnalyzer { get; set; } Property Value Type Description IQueryableAnalyzer | Improve this Doc View Source RenameParameterExpression Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from it . Default value is false. Declaration public bool RenameParameterExpression { get; set; } Property Value Type Description Boolean | Improve this Doc View Source ResolveTypesBySimpleName By default finding types by a simple name is not supported. Use this flag to use the CustomTypeProvider to resolve types by a simple name like \"Employee\" instead of \"MyDatabase.Entities.Employee\". Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution. Default value is false. Declaration public bool ResolveTypesBySimpleName { get; set; } Property Value Type Description Boolean | Improve this Doc View Source SupportEnumerationsFromSystemNamespace Support enumeration-types from the System namespace in mscorlib. An example could be \"StringComparison\". Default value is true. Declaration public bool SupportEnumerationsFromSystemNamespace { get; set; } Property Value Type Description Boolean | Improve this Doc View Source UseDynamicObjectClassForAnonymousTypes Gets or sets a value indicating whether to use dynamic object class for anonymous types. Default value is false. Declaration public bool UseDynamicObjectClassForAnonymousTypes { get; set; } Property Value Type Description Boolean | Improve this Doc View Source UseParameterizedNamesInDynamicQuery Use Parameterized Names in generated dynamic SQL query. See https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd Default value is false. Declaration public bool UseParameterizedNamesInDynamicQuery { get; set; } Property Value Type Description Boolean" + "api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html": { + "href": "api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html", + "title": "Class DynamicQueryableExtensions", + "keywords": "Class DynamicQueryableExtensions Provides a set of static (Shared in Visual Basic) methods for querying data structures that implement IQueryable . It allows dynamic string based querying. Very handy when, at compile time, you don't know the type of queries that will be generated, or when downstream components only return column names to sort and filter by. Inheritance Object DynamicQueryableExtensions Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicQueryableExtensions Methods | Improve this Doc View Source Aggregate(IQueryable, String, String) Dynamically runs an aggregate function on the IQueryable. Declaration public static object Aggregate(this IQueryable source, string function, string member) Parameters Type Name Description IQueryable source The IQueryable data source. String function The name of the function to run. Can be Sum, Average, Min or Max. String member The name of the property to aggregate over. Returns Type Description Object The value of the aggregate function run over the specified property. | Improve this Doc View Source All(IQueryable, ParsingConfig, String, Object[]) Determines whether all the elements of a sequence satisfy a condition. Declaration [PublicAPI] public static bool All(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence whose elements to test for a condition. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Boolean true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. | Improve this Doc View Source All(IQueryable, String, Object[]) Determines whether all the elements of a sequence satisfy a condition. Declaration [PublicAPI] public static bool All(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence whose elements to test for a condition. String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Boolean true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. | Improve this Doc View Source Any(IQueryable) Determines whether a sequence contains any elements. Declaration public static bool Any(this IQueryable source) Parameters Type Name Description IQueryable source A sequence to check for being empty. Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Any(); | Improve this Doc View Source Any(IQueryable, ParsingConfig, String, Object[]) Determines whether a sequence contains any elements. Declaration [PublicAPI] public static bool Any(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence to check for being empty. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Any(\"Income > 50\"); var result2 = queryable.Any(\"Income > @0\", 50); var result3 = queryable.Select(\"Roles.Any()\"); | Improve this Doc View Source Any(IQueryable, LambdaExpression) Determines whether a sequence contains any elements. Declaration public static bool Any(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence to check for being empty. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. | Improve this Doc View Source Any(IQueryable, String, Object[]) Determines whether a sequence contains any elements. Declaration public static bool Any(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Boolean true if the source sequence contains any elements; otherwise, false. | Improve this Doc View Source AsDynamicEnumerable(IQueryable) Returns the input typed as IEnumerable of Object ./> Declaration public static IEnumerable AsDynamicEnumerable(this IQueryable source) Parameters Type Name Description IQueryable source The sequence to type as IEnumerable of Object . Returns Type Description IEnumerable < Object > The input typed as IEnumerable of Object . | Improve this Doc View Source Average(IQueryable) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average(this IQueryable source) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the average of. Returns Type Description Double The average of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Average(); var result2 = queryable.Select(\"Roles.Average()\"); | Improve this Doc View Source Average(IQueryable, ParsingConfig, String, Object[]) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the average of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Double The average of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Average(\"Income\"); | Improve this Doc View Source Average(IQueryable, LambdaExpression) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the average of. LambdaExpression lambda A Lambda Expression. Returns Type Description Double The average of the values in the sequence. | Improve this Doc View Source Average(IQueryable, String, Object[]) Computes the average of a sequence of numeric values. Declaration [PublicAPI] public static double Average(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Double The average of the values in the sequence. | Improve this Doc View Source Cast(IQueryable, ParsingConfig, String) Converts the elements of an IQueryable to the specified type. Declaration public static IQueryable Cast(this IQueryable source, ParsingConfig config, string typeName) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be converted. ParsingConfig config The ParsingConfig . String typeName The type to convert the elements of source to. Returns Type Description IQueryable An IQueryable that contains each element of the source sequence converted to the specified type. | Improve this Doc View Source Cast(IQueryable, String) Converts the elements of an IQueryable to the specified type. Declaration public static IQueryable Cast(this IQueryable source, string typeName) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be converted. String typeName The type to convert the elements of source to. Returns Type Description IQueryable An IQueryable that contains each element of the source sequence converted to the specified type. | Improve this Doc View Source Cast(IQueryable, Type) Converts the elements of an IQueryable to the specified type. Declaration public static IQueryable Cast(this IQueryable source, Type type) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be converted. Type type The type to convert the elements of source to. Returns Type Description IQueryable An IQueryable that contains each element of the source sequence converted to the specified type. | Improve this Doc View Source Count(IQueryable) Returns the number of elements in a sequence. Declaration public static int Count(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. Returns Type Description Int32 The number of elements in the input sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Count(); | Improve this Doc View Source Count(IQueryable, ParsingConfig, String, Object[]) Returns the number of elements in a sequence. Declaration [PublicAPI] public static int Count(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Int32 The number of elements in the specified sequence that satisfies a condition. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Count(\"Income > 50\"); var result2 = queryable.Count(\"Income > @0\", 50); var result3 = queryable.Select(\"Roles.Count()\"); | Improve this Doc View Source Count(IQueryable, LambdaExpression) Returns the number of elements in a sequence. Declaration public static int Count(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Int32 The number of elements in the specified sequence that satisfies a condition. | Improve this Doc View Source Count(IQueryable, String, Object[]) Returns the number of elements in a sequence. Declaration public static int Count(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Int32 The number of elements in the specified sequence that satisfies a condition. | Improve this Doc View Source DefaultIfEmpty(IQueryable) Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty. Declaration public static IQueryable DefaultIfEmpty(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return a default value for if empty. Returns Type Description IQueryable An IQueryable that contains default if source is empty; otherwise, source. Examples IQueryable queryable = employees.DefaultIfEmpty(); | Improve this Doc View Source DefaultIfEmpty(IQueryable, Object) Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty. Declaration public static IQueryable DefaultIfEmpty(this IQueryable source, object defaultValue) Parameters Type Name Description IQueryable source The IQueryable to return a default value for if empty. Object defaultValue The value to return if the sequence is empty. Returns Type Description IQueryable An IQueryable that contains defaultValue if source is empty; otherwise, source. Examples IQueryable queryable = employees.DefaultIfEmpty(new Employee()); | Improve this Doc View Source Distinct(IQueryable) Returns distinct elements from a sequence by using the default equality comparer to compare values. Declaration public static IQueryable Distinct(this IQueryable source) Parameters Type Name Description IQueryable source The sequence to remove duplicate elements from. Returns Type Description IQueryable An IQueryable that contains distinct elements from the source sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Distinct(); var result2 = queryable.Select(\"Roles.Distinct()\"); | Improve this Doc View Source First(IQueryable) Returns the first element of a sequence. Declaration public static object First(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. Returns Type Description Object The first element in source. | Improve this Doc View Source First(IQueryable, ParsingConfig, String, Object[]) Returns the first element of a sequence that satisfies a specified condition. Declaration [PublicAPI] public static object First(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source First(IQueryable, LambdaExpression) Returns the first element of a sequence that satisfies a specified condition. Declaration public static object First(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source First(IQueryable, String, Object[]) Returns the first element of a sequence that satisfies a specified condition. Declaration public static object First(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source FirstOrDefault(IQueryable) Returns the first element of a sequence, or a default value if the sequence contains no elements. Declaration public static object FirstOrDefault(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. Returns Type Description Object default if source is empty; otherwise, the first element in source. | Improve this Doc View Source FirstOrDefault(IQueryable, ParsingConfig, String, Object[]) Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found. Declaration [PublicAPI] public static object FirstOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. | Improve this Doc View Source FirstOrDefault(IQueryable, LambdaExpression) Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found. Declaration public static object FirstOrDefault(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the first element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. | Improve this Doc View Source FirstOrDefault(IQueryable, String, Object[]) Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found. Declaration public static object FirstOrDefault(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, IEqualityComparer, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, IEqualityComparer equalityComparer, params object[] args) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. IEqualityComparer equalityComparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration [PublicAPI] public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, params object[] args) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. Examples var groupResult1 = queryable.GroupBy(\"NumberPropertyAsKey\"); var groupResult2 = queryable.GroupBy(\"new (NumberPropertyAsKey, StringPropertyAsKey)\"); | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, String) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. String resultSelector A string expression to specify a result value from each group. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. Examples var groupResult1 = queryable.GroupBy(\"NumberPropertyAsKey\", \"StringProperty\"); var groupResult2 = queryable.GroupBy(\"new (NumberPropertyAsKey, StringPropertyAsKey)\", \"new (StringProperty1, StringProperty2)\"); | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, String, IEqualityComparer) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer equalityComparer) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. String resultSelector A string expression to specify a result value from each group. IEqualityComparer equalityComparer The comparer to use. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, String, IEqualityComparer, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer equalityComparer, object[] args) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. String resultSelector A string expression to specify a result value from each group. IEqualityComparer equalityComparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, ParsingConfig, String, String, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration [PublicAPI] public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, object[] args) Parameters Type Name Description IQueryable source A IQueryable whose elements to group. ParsingConfig config The ParsingConfig . String keySelector A string expression to specify the key for each element. String resultSelector A string expression to specify a result value from each group. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. Examples var groupResult1 = queryable.GroupBy(\"NumberPropertyAsKey\", \"StringProperty\"); var groupResult2 = queryable.GroupBy(\"new (NumberPropertyAsKey, StringPropertyAsKey)\", \"new (StringProperty1, StringProperty2)\"); | Improve this Doc View Source GroupBy(IQueryable, String, IEqualityComparer, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, string keySelector, IEqualityComparer equalityComparer, params object[] args) Parameters Type Name Description IQueryable source String keySelector IEqualityComparer equalityComparer Object [] args Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, String, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration [PublicAPI] public static IQueryable GroupBy(this IQueryable source, string keySelector, params object[] args) Parameters Type Name Description IQueryable source String keySelector Object [] args Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, String, String) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector) Parameters Type Name Description IQueryable source String keySelector String resultSelector Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, String, String, IEqualityComparer) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer) Parameters Type Name Description IQueryable source String keySelector String resultSelector IEqualityComparer equalityComparer Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, String, String, IEqualityComparer, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer, object[] args) Parameters Type Name Description IQueryable source String keySelector String resultSelector IEqualityComparer equalityComparer Object [] args Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupBy(IQueryable, String, String, Object[]) Groups the elements of a sequence according to a specified key string function and creates a result value from each group and its key. Declaration [PublicAPI] public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, object[] args) Parameters Type Name Description IQueryable source String keySelector String resultSelector Object [] args Returns Type Description IQueryable A IQueryable where each element represents a projection over a group and its key. | Improve this Doc View Source GroupByMany(IEnumerable, Func[]) Groups the elements of a sequence according to multiple specified key functions and creates a result value from each group (and subgroups) and its key. Declaration public static IEnumerable GroupByMany(this IEnumerable source, params Func[] keySelectors) Parameters Type Name Description IEnumerable source A IEnumerable whose elements to group. Func [] keySelectors Lambda expressions to specify the keys for each element. Returns Type Description IEnumerable < GroupResult > A IEnumerable of type GroupResult where each element represents a projection over a group, its key, and its subgroups. Type Parameters Name Description TElement | Improve this Doc View Source GroupByMany(IEnumerable, ParsingConfig, String[]) Groups the elements of a sequence according to multiple specified key string functions and creates a result value from each group (and subgroups) and its key. Declaration public static IEnumerable GroupByMany(this IEnumerable source, ParsingConfig config, params string[] keySelectors) Parameters Type Name Description IEnumerable source A IEnumerable whose elements to group. ParsingConfig config The ParsingConfig . String [] keySelectors String expressions to specify the keys for each element. Returns Type Description IEnumerable < GroupResult > A IEnumerable of type GroupResult where each element represents a projection over a group, its key, and its subgroups. Type Parameters Name Description TElement | Improve this Doc View Source GroupByMany(IEnumerable, String[]) Groups the elements of a sequence according to multiple specified key string functions and creates a result value from each group (and subgroups) and its key. Declaration public static IEnumerable GroupByMany(this IEnumerable source, params string[] keySelectors) Parameters Type Name Description IEnumerable source String [] keySelectors Returns Type Description IEnumerable < GroupResult > A IEnumerable of type GroupResult where each element represents a projection over a group, its key, and its subgroups. Type Parameters Name Description TElement | Improve this Doc View Source GroupJoin(IQueryable, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys. Declaration public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer IEnumerable inner String outerKeySelector String innerKeySelector String resultSelector Object [] args Returns Type Description IQueryable An IQueryable obtained by performing a grouped join on two sequences. | Improve this Doc View Source GroupJoin(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys. Declaration public static IQueryable GroupJoin(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer The first sequence to join. ParsingConfig config The ParsingConfig . IEnumerable inner The sequence to join to the first sequence. String outerKeySelector A dynamic function to extract the join key from each element of the first sequence. String innerKeySelector A dynamic function to extract the join key from each element of the second sequence. String resultSelector A dynamic function to create a result element from an element from the first sequence and a collection of matching elements from the second sequence. Object [] args An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable obtained by performing a grouped join on two sequences. | Improve this Doc View Source Join(IQueryable, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. Declaration public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer IEnumerable inner String outerKeySelector String innerKeySelector String resultSelector Object [] args Returns Type Description IQueryable An IQueryable obtained by performing an inner join on two sequences. | Improve this Doc View Source Join(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. Declaration public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer The first sequence to join. ParsingConfig config The ParsingConfig . IEnumerable inner The sequence to join to the first sequence. String outerKeySelector A dynamic function to extract the join key from each element of the first sequence. String innerKeySelector A dynamic function to extract the join key from each element of the second sequence. String resultSelector A dynamic function to create a result element from two matching elements. Object [] args An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable obtained by performing an inner join on two sequences. | Improve this Doc View Source Join(IQueryable, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. Declaration public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer IEnumerable inner String outerKeySelector String innerKeySelector String resultSelector Object [] args Returns Type Description IQueryable An IQueryable that has elements of type TResult obtained by performing an inner join on two sequences. Type Parameters Name Description TElement The type of the elements of both sequences, and the result. Remarks This overload only works on elements where both sequences and the resulting element match. | Improve this Doc View Source Join(IQueryable, ParsingConfig, IEnumerable, String, String, String, Object[]) Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. Declaration public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object[] args) Parameters Type Name Description IQueryable outer The first sequence to join. ParsingConfig config The ParsingConfig . IEnumerable inner The sequence to join to the first sequence. String outerKeySelector A dynamic function to extract the join key from each element of the first sequence. String innerKeySelector A dynamic function to extract the join key from each element of the second sequence. String resultSelector A dynamic function to create a result element from two matching elements. Object [] args An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable that has elements of type TResult obtained by performing an inner join on two sequences. Type Parameters Name Description TElement The type of the elements of both sequences, and the result. Remarks This overload only works on elements where both sequences and the resulting element match. | Improve this Doc View Source Last(IQueryable) Returns the last element of a sequence. Declaration public static object Last(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. Returns Type Description Object The last element in source. | Improve this Doc View Source Last(IQueryable, ParsingConfig, String, Object[]) Returns the last element of a sequence that satisfies a specified condition. Declaration public static object Last(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Last(IQueryable, LambdaExpression) Returns the last element of a sequence that satisfies a specified condition. Declaration public static object Last(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Last(IQueryable, String, Object[]) Returns the last element of a sequence that satisfies a specified condition. Declaration public static object Last(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source LastOrDefault(IQueryable) Returns the last element of a sequence, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. Returns Type Description Object default if source is empty; otherwise, the last element in source. | Improve this Doc View Source LastOrDefault(IQueryable, ParsingConfig, String, Object[]) Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source LastOrDefault(IQueryable, LambdaExpression) Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source LastOrDefault(IQueryable, String, Object[]) Returns the last element of a sequence that satisfies a specified condition, or a default value if the sequence contains no elements. Declaration public static object LastOrDefault(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source LongCount(IQueryable) Returns the number of elements in a sequence. Declaration public static long LongCount(this IQueryable source) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. Returns Type Description Int64 The number of elements in the input sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.LongCount(); | Improve this Doc View Source LongCount(IQueryable, ParsingConfig, String, Object[]) Returns the number of elements in a sequence. Declaration [PublicAPI] public static long LongCount(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Int64 The number of elements in the specified sequence that satisfies a condition. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.LongCount(\"Income > 50\"); var result2 = queryable.LongCount(\"Income > @0\", 50); var result3 = queryable.Select(\"Roles.LongCount()\"); | Improve this Doc View Source LongCount(IQueryable, LambdaExpression) Returns the number of elements in a sequence. Declaration public static long LongCount(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable that contains the elements to be counted. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Int64 The number of elements in the specified sequence that satisfies a condition. | Improve this Doc View Source LongCount(IQueryable, String, Object[]) Returns the number of elements in a sequence. Declaration public static long LongCount(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Int64 The number of elements in the specified sequence that satisfies a condition. | Improve this Doc View Source Max(IQueryable) Computes the max element of a sequence. Declaration [PublicAPI] public static object Max(this IQueryable source) Parameters Type Name Description IQueryable source A sequence of values to calculate find the max for. Returns Type Description Object The max element in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Max(); var result2 = queryable.Select(\"Roles.Max()\"); | Improve this Doc View Source Max(IQueryable, ParsingConfig, String, Object[]) Computes the max element of a sequence. Declaration [PublicAPI] public static object Max(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to calculate find the max for. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The max element in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Max(\"Income\"); | Improve this Doc View Source Max(IQueryable, LambdaExpression) Computes the max element of a sequence. Declaration [PublicAPI] public static object Max(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence of values to calculate find the max for. LambdaExpression lambda A Lambda Expression. Returns Type Description Object The max element in the sequence. | Improve this Doc View Source Max(IQueryable, String, Object[]) Computes the max element of a sequence. Declaration [PublicAPI] public static object Max(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The max element in the sequence. | Improve this Doc View Source Min(IQueryable) Computes the min element of a sequence. Declaration [PublicAPI] public static object Min(this IQueryable source) Parameters Type Name Description IQueryable source A sequence of values to calculate find the min for. Returns Type Description Object The min element in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Min(); var result2 = queryable.Select(\"Roles.Min()\"); | Improve this Doc View Source Min(IQueryable, ParsingConfig, String, Object[]) Computes the min element of a sequence. Declaration [PublicAPI] public static object Min(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to calculate find the min for. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The min element in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Min(\"Income\"); | Improve this Doc View Source Min(IQueryable, LambdaExpression) Computes the min element of a sequence. Declaration [PublicAPI] public static object Min(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence of values to calculate find the min for. LambdaExpression lambda A Lambda Expression. Returns Type Description Object The min element in the sequence. | Improve this Doc View Source Min(IQueryable, String, Object[]) Computes the min element of a sequence. Declaration [PublicAPI] public static object Min(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The min element in the sequence. | Improve this Doc View Source OfType(IQueryable, ParsingConfig, String) Filters the elements of an IQueryable based on a specified type. Declaration public static IQueryable OfType(this IQueryable source, ParsingConfig config, string typeName) Parameters Type Name Description IQueryable source An IQueryable whose elements to filter. ParsingConfig config The ParsingConfig . String typeName The type to filter the elements of the sequence on. Returns Type Description IQueryable A collection that contains the elements from source that have the type. | Improve this Doc View Source OfType(IQueryable, String) Filters the elements of an IQueryable based on a specified type. Declaration public static IQueryable OfType(this IQueryable source, string typeName) Parameters Type Name Description IQueryable source An IQueryable whose elements to filter. String typeName The type to filter the elements of the sequence on. Returns Type Description IQueryable A collection that contains the elements from source that have the type. | Improve this Doc View Source OfType(IQueryable, Type) Filters the elements of an IQueryable based on a specified type. Declaration public static IQueryable OfType(this IQueryable source, Type type) Parameters Type Name Description IQueryable source An IQueryable whose elements to filter. Type type The type to filter the elements of the sequence on. Returns Type Description IQueryable A collection that contains the elements from source that have the type. | Improve this Doc View Source OrderBy(IQueryable, ParsingConfig, String, IComparer, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. IComparer comparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . | Improve this Doc View Source OrderBy(IQueryable, ParsingConfig, String, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Examples var resultSingle = queryable.OrderBy(\"NumberProperty\"); var resultSingleDescending = queryable.OrderBy(\"NumberProperty DESC\"); var resultMultiple = queryable.OrderBy(\"NumberProperty, StringProperty DESC\"); | Improve this Doc View Source OrderBy(IQueryable, String, IComparer, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IQueryable source String ordering IComparer comparer Object [] args Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . | Improve this Doc View Source OrderBy(IQueryable, String, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object[] args) Parameters Type Name Description IQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . | Improve this Doc View Source OrderBy(IQueryable, ParsingConfig, String, IComparer, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. IComparer comparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. | Improve this Doc View Source OrderBy(IQueryable, ParsingConfig, String, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. Examples var resultSingle = queryable.OrderBy(\"NumberProperty\"); var resultSingleDescending = queryable.OrderBy(\"NumberProperty DESC\"); var resultMultiple = queryable.OrderBy(\"NumberProperty, StringProperty\"); | Improve this Doc View Source OrderBy(IQueryable, String, IComparer, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to order. String ordering An expression string to indicate values to order by. IComparer comparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. | Improve this Doc View Source OrderBy(IQueryable, String, Object[]) Sorts the elements of a sequence in ascending or descending order according to a key. Declaration public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object[] args) Parameters Type Name Description IQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. | Improve this Doc View Source Page(IQueryable, Int32, Int32) Returns the elements as paged. Declaration public static IQueryable Page(this IQueryable source, int page, int pageSize) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Returns Type Description IQueryable A IQueryable that contains the paged elements. | Improve this Doc View Source Page(IQueryable, Int32, Int32) Returns the elements as paged. Declaration public static IQueryable Page(this IQueryable source, int page, int pageSize) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Returns Type Description IQueryable A IQueryable that contains the paged elements. Type Parameters Name Description TSource The type of the source. | Improve this Doc View Source PageResult(IQueryable, Int32, Int32, Nullable) Returns the elements as paged and include the CurrentPage, PageCount, PageSize and RowCount. Declaration public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Nullable < Int32 > rowCount If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq Count() . Returns Type Description PagedResult PagedResult | Improve this Doc View Source PageResult(IQueryable, Int32, Int32, Nullable) Returns the elements as paged and include the CurrentPage, PageCount, PageSize and RowCount. Declaration public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) Parameters Type Name Description IQueryable source The IQueryable to return elements from. Int32 page The page to return. Int32 pageSize The number of elements per page. Nullable < Int32 > rowCount If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq Count() . Returns Type Description PagedResult PagedResult{TSource} Type Parameters Name Description TSource The type of the source. | Improve this Doc View Source Reverse(IQueryable) Inverts the order of the elements in a sequence. Declaration public static IQueryable Reverse(this IQueryable source) Parameters Type Name Description IQueryable source A sequence of values to reverse. Returns Type Description IQueryable A IQueryable whose elements correspond to those of the input sequence in reverse order. | Improve this Doc View Source Select(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence into a new form. Declaration public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Examples var singleField = queryable.Select(\"StringProperty\"); var dynamicObject = queryable.Select(\"new (StringProperty1, StringProperty2 as OtherStringPropertyName)\"); | Improve this Doc View Source Select(IQueryable, ParsingConfig, Type, String, Object[]) Projects each element of a sequence into a new class of type TResult. Details see http://solutionizing.net/category/linq/ Declaration public static IQueryable Select(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . Type resultType The result type. String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Examples var users = queryable.Select(typeof(User), \"new (Username, Pwd as Password)\"); | Improve this Doc View Source Select(IQueryable, String, Object[]) Projects each element of a sequence into a new form. Declaration public static IQueryable Select(this IQueryable source, string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. | Improve this Doc View Source Select(IQueryable, Type, String, Object[]) Projects each element of a sequence into a new class of type TResult. Details see http://solutionizing.net/category/linq/ Declaration public static IQueryable Select(this IQueryable source, Type resultType, string selector, params object[] args) Parameters Type Name Description IQueryable source Type resultType String selector Object [] args Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. | Improve this Doc View Source Select(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence into a new class of type TResult. Details see http://solutionizing.net/category/linq/ . Declaration public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Type Parameters Name Description TResult The type of the result. Examples var users = queryable.Select(\"new (Username, Pwd as Password)\"); | Improve this Doc View Source Select(IQueryable, String, Object[]) Projects each element of a sequence into a new class of type TResult. Details see http://solutionizing.net/category/linq/ . Declaration public static IQueryable Select(this IQueryable source, string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a projection string on each element of source. Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Examples var roles = users.SelectMany(\"Roles\"); | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, String, Object[], Object[]) Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned. Declaration public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string collectionSelector, string resultSelector, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String collectionSelector A projection function to apply to each element of the input sequence. String resultSelector A projection function to apply to each element of each intermediate sequence. Should only use x and y as parameter names. Object [] collectionSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Object [] resultSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element. Examples // TODO | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, String, String, String, Object[], Object[]) Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned. Declaration public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string collectionSelector, string resultSelector, string collectionParameterName, string resultParameterName, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String collectionSelector A projection function to apply to each element of the input sequence. String resultSelector A projection function to apply to each element of each intermediate sequence. String collectionParameterName The name from collectionParameter to use. Default is x. String resultParameterName The name from resultParameterName to use. Default is y. Object [] collectionSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Object [] resultSelectorArgs An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element. Examples // TODO | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, Type, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . Type resultType The result type. String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Examples var permissions = users.SelectMany(typeof(Permission), \"Roles.SelectMany(Permissions)\"); | Improve this Doc View Source SelectMany(IQueryable, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany(this IQueryable source, string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. | Improve this Doc View Source SelectMany(IQueryable, String, String, Object[], Object[]) Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned. Declaration public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source String collectionSelector String resultSelector Object [] collectionSelectorArgs Object [] resultSelectorArgs Returns Type Description IQueryable An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element. | Improve this Doc View Source SelectMany(IQueryable, String, String, String, String, Object[], Object[]) Projects each element of a sequence to an IQueryable and invokes a result selector function on each element therein. The resulting values from each intermediate sequence are combined into a single, one-dimensional sequence and returned. Declaration public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, string collectionParameterName, string resultParameterName, object[] collectionSelectorArgs = null, params object[] resultSelectorArgs) Parameters Type Name Description IQueryable source String collectionSelector String resultSelector String collectionParameterName String resultParameterName Object [] collectionSelectorArgs Object [] resultSelectorArgs Returns Type Description IQueryable An IQueryable whose elements are the result of invoking the one-to-many projection function collectionSelector on each element of source and then mapping each of those sequence elements and their corresponding source element to a result element. | Improve this Doc View Source SelectMany(IQueryable, Type, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany(this IQueryable source, Type resultType, string selector, params object[] args) Parameters Type Name Description IQueryable source Type resultType String selector Object [] args Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. | Improve this Doc View Source SelectMany(IQueryable, ParsingConfig, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object[] args) Parameters Type Name Description IQueryable source A sequence of values to project. ParsingConfig config The ParsingConfig . String selector A projection string expression to apply to each element. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Type Parameters Name Description TResult The type of the result. Examples var permissions = users.SelectMany(\"Roles.SelectMany(Permissions)\"); | Improve this Doc View Source SelectMany(IQueryable, String, Object[]) Projects each element of a sequence to an IQueryable and combines the resulting sequences into one sequence. Declaration public static IQueryable SelectMany(this IQueryable source, string selector, params object[] args) Parameters Type Name Description IQueryable source String selector Object [] args Returns Type Description IQueryable An IQueryable whose elements are the result of invoking a one-to-many projection function on each element of the input sequence. Type Parameters Name Description TResult The type of the result. | Improve this Doc View Source Single(IQueryable) Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single(this IQueryable source) Parameters Type Name Description IQueryable source A IQueryable to return the single element of. Returns Type Description Object The single element of the input sequence. | Improve this Doc View Source Single(IQueryable, ParsingConfig, String, Object[]) Returns the only element of a sequence that satisfies a specified condition, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Single(IQueryable, LambdaExpression) Returns the only element of a sequence that satisfies a specified condition, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Single(IQueryable, String, Object[]) Returns the only element of a sequence that satisfies a specified condition, and throws an exception if there is not exactly one element in the sequence. Declaration public static object Single(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source SingleOrDefault(IQueryable) Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence. Declaration public static object SingleOrDefault(this IQueryable source) Parameters Type Name Description IQueryable source A IQueryable to return the single element of. Returns Type Description Object The single element of the input sequence, or default if the sequence contains no elements. | Improve this Doc View Source SingleOrDefault(IQueryable, ParsingConfig, String, Object[]) Returns the only element of a sequence that satisfies a specified condition or a default value if the sequence is empty; and throws an exception if there is not exactly one element in the sequence. Declaration public static object SingleOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source SingleOrDefault(IQueryable, LambdaExpression) Returns the only element of a sequence that satisfies a specified condition or a default value if the sequence is empty; and throws an exception if there is not exactly one element in the sequence. Declaration public static object SingleOrDefault(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source The IQueryable to return the last element of. LambdaExpression lambda A cached Lambda Expression. Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source SingleOrDefault(IQueryable, String, Object[]) Returns the only element of a sequence that satisfies a specified condition or a default value if the sequence is empty; and throws an exception if there is not exactly one element in the sequence. Declaration public static object SingleOrDefault(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The first element in source that passes the test in predicate. | Improve this Doc View Source Skip(IQueryable, Int32) Bypasses a specified number of elements in a sequence and then returns the remaining elements. Declaration public static IQueryable Skip(this IQueryable source, int count) Parameters Type Name Description IQueryable source A IQueryable to return elements from. Int32 count The number of elements to skip before returning the remaining elements. Returns Type Description IQueryable A IQueryable that contains elements that occur after the specified index in the input sequence. | Improve this Doc View Source SkipWhile(IQueryable, ParsingConfig, String, Object[]) Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. Declaration public static IQueryable SkipWhile(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence to check for being empty. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.SkipWhile(\"Income > 50\"); var result2 = queryable.SkipWhile(\"Income > @0\", 50); | Improve this Doc View Source SkipWhile(IQueryable, String, Object[]) Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. Declaration public static IQueryable SkipWhile(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable An IQueryable that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate. | Improve this Doc View Source Sum(IQueryable) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum(this IQueryable source) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the sum of. Returns Type Description Object The sum of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.Sum(); var result2 = queryable.Select(\"Roles.Sum()\"); | Improve this Doc View Source Sum(IQueryable, ParsingConfig, String, Object[]) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the sum of. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description Object The sum of the values in the sequence. Examples IQueryable queryable = employees.AsQueryable(); var result = queryable.Sum(\"Income\"); | Improve this Doc View Source Sum(IQueryable, LambdaExpression) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source A sequence of numeric values to calculate the sum of. LambdaExpression lambda A Lambda Expression. Returns Type Description Object The sum of the values in the sequence. | Improve this Doc View Source Sum(IQueryable, String, Object[]) Computes the sum of a sequence of numeric values. Declaration [PublicAPI] public static object Sum(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description Object The sum of the values in the sequence. | Improve this Doc View Source Take(IQueryable, Int32) Returns a specified number of contiguous elements from the start of a sequence. Declaration public static IQueryable Take(this IQueryable source, int count) Parameters Type Name Description IQueryable source The sequence to return elements from. Int32 count The number of elements to return. Returns Type Description IQueryable A IQueryable that contains the specified number of elements from the start of source. | Improve this Doc View Source TakeWhile(IQueryable, ParsingConfig, String, Object[]) Returns elements from a sequence as long as a specified condition is true. Declaration public static IQueryable TakeWhile(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A sequence to check for being empty. ParsingConfig config The ParsingConfig . String predicate A function to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable An IQueryable that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes. Examples IQueryable queryable = employees.AsQueryable(); var result1 = queryable.TakeWhile(\"Income > 50\"); var result2 = queryable.TakeWhile(\"Income > @0\", 50); | Improve this Doc View Source TakeWhile(IQueryable, String, Object[]) Returns elements from a sequence as long as a specified condition is true. Declaration public static IQueryable TakeWhile(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable An IQueryable that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes. | Improve this Doc View Source ThenBy(IOrderedQueryable, ParsingConfig, String, IComparer, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. IComparer comparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . | Improve this Doc View Source ThenBy(IOrderedQueryable, ParsingConfig, String, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . Examples var result = queryable.OrderBy(\"LastName\"); var resultSingle = result.OrderBy(\"NumberProperty\"); var resultSingleDescending = result.OrderBy(\"NumberProperty DESC\"); var resultMultiple = result.OrderBy(\"NumberProperty, StringProperty DESC\"); | Improve this Doc View Source ThenBy(IOrderedQueryable, String, IComparer, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IOrderedQueryable source String ordering IComparer comparer Object [] args Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . | Improve this Doc View Source ThenBy(IOrderedQueryable, String, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable A IQueryable whose elements are sorted according to the specified ordering . | Improve this Doc View Source ThenBy(IOrderedQueryable, ParsingConfig, String, IComparer, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. IComparer comparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IOrderedQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. | Improve this Doc View Source ThenBy(IOrderedQueryable, ParsingConfig, String, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. ParsingConfig config The ParsingConfig . String ordering An expression string to indicate values to order by. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IOrderedQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. Examples var result = queryable.OrderBy(\"LastName\"); var resultSingle = result.ThenBy(\"NumberProperty\"); var resultSingleDescending = result.ThenBy(\"NumberProperty DESC\"); var resultMultiple = result.ThenBy(\"NumberProperty, StringProperty\"); | Improve this Doc View Source ThenBy(IOrderedQueryable, String, IComparer, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object[] args) Parameters Type Name Description IOrderedQueryable source A sequence of values to order. String ordering An expression string to indicate values to order by. IComparer comparer The comparer to use. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IOrderedQueryable A IOrderedQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. | Improve this Doc View Source ThenBy(IOrderedQueryable, String, Object[]) Performs a subsequent ordering of the elements in a sequence in ascending order according to a key. Declaration public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object[] args) Parameters Type Name Description IOrderedQueryable source String ordering Object [] args Returns Type Description IOrderedQueryable A IOrderedQueryable whose elements are sorted according to the specified ordering . Type Parameters Name Description TSource The type of the elements of source. | Improve this Doc View Source Where(IQueryable, ParsingConfig, String, Object[]) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A IQueryable to filter. ParsingConfig config The ParsingConfig . String predicate An expression string to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate. Examples var result1 = queryable.Where(\"NumberProperty = 1\"); var result2 = queryable.Where(\"NumberProperty = @0\", 1); var result3 = queryable.Where(\"StringProperty = null\"); var result4 = queryable.Where(\"StringProperty = \\\"abc\\\"\"); var result5 = queryable.Where(\"StringProperty = @0\", \"abc\"); | Improve this Doc View Source Where(IQueryable, LambdaExpression) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source A IQueryable to filter. LambdaExpression lambda A cached Lambda Expression. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by LambdaExpression. | Improve this Doc View Source Where(IQueryable, String, Object[]) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate. | Improve this Doc View Source Where(IQueryable, ParsingConfig, String, Object[]) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object[] args) Parameters Type Name Description IQueryable source A IQueryable to filter. ParsingConfig config The ParsingConfig . String predicate An expression string to test each element for a condition. Object [] args An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate. Type Parameters Name Description TSource The type of the elements of source. Examples var result1 = queryable.Where(\"NumberProperty = 1\"); var result2 = queryable.Where(\"NumberProperty = @0\", 1); var result3 = queryable.Where(\"StringProperty = null\"); var result4 = queryable.Where(\"StringProperty = \\\"abc\\\"\"); var result5 = queryable.Where(\"StringProperty = @0\", \"abc\"); | Improve this Doc View Source Where(IQueryable, LambdaExpression) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where(this IQueryable source, LambdaExpression lambda) Parameters Type Name Description IQueryable source LambdaExpression lambda A cached Lambda Expression. Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by LambdaExpression. Type Parameters Name Description TSource | Improve this Doc View Source Where(IQueryable, String, Object[]) Filters a sequence of values based on a predicate. Declaration public static IQueryable Where(this IQueryable source, string predicate, params object[] args) Parameters Type Name Description IQueryable source String predicate Object [] args Returns Type Description IQueryable A IQueryable that contains elements from the input sequence that satisfy the condition specified by predicate. Type Parameters Name Description TSource The type of the elements of source." }, - "api/System.Linq.Dynamic.Core.Parser.html": { - "href": "api/System.Linq.Dynamic.Core.Parser.html", - "title": "Namespace System.Linq.Dynamic.Core.Parser", - "keywords": "Namespace System.Linq.Dynamic.Core.Parser Classes ExpressionParser ExpressionParser ExpressionPromoter NumberParser NumberParser Interfaces IExpressionPromoter Expression promoter is used to promote object or value types to their destination type when an automatic promotion is available such as: int to int?" + "api/System.Linq.Dynamic.Core.Exceptions.html": { + "href": "api/System.Linq.Dynamic.Core.Exceptions.html", + "title": "Namespace System.Linq.Dynamic.Core.Exceptions", + "keywords": "Namespace System.Linq.Dynamic.Core.Exceptions Classes ParseException Represents errors that occur while parsing dynamic linq string expressions." }, - "api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html": { - "href": "api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html", - "title": "Class ExpressionPromoter", - "keywords": "Class ExpressionPromoter Inheritance Object ExpressionPromoter Implements IExpressionPromoter Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public class ExpressionPromoter : IExpressionPromoter Constructors | Improve this Doc View Source ExpressionPromoter(ParsingConfig) Initializes a new instance of the ExpressionPromoter class. Declaration public ExpressionPromoter(ParsingConfig config) Parameters Type Name Description ParsingConfig config The ParsingConfig. Methods | Improve this Doc View Source Promote(Expression, Type, Boolean, Boolean) Declaration public virtual Expression Promote(Expression expr, Type type, bool exact, bool convertExpr) Parameters Type Name Description Expression expr Type type Boolean exact Boolean convertExpr Returns Type Description Expression Implements IExpressionPromoter" + "api/System.Linq.Dynamic.Core.Exceptions.ParseException.html": { + "href": "api/System.Linq.Dynamic.Core.Exceptions.ParseException.html", + "title": "Class ParseException", + "keywords": "Class ParseException Represents errors that occur while parsing dynamic linq string expressions. Inheritance Object Exception ParseException Implements ISerializable _Exception Inherited Members Exception.GetBaseException() Exception.GetType() Exception.Message Exception.Data Exception.InnerException Exception.TargetSite Exception.StackTrace Exception.HelpLink Exception.Source Exception.HResult Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Exceptions Assembly : System.Linq.Dynamic.Core.dll Syntax [Serializable] public sealed class ParseException : Exception, ISerializable, _Exception Constructors | Improve this Doc View Source ParseException(String, Int32) Initializes a new instance of the ParseException class with a specified error message and position. Declaration public ParseException(string message, int position) Parameters Type Name Description String message The message that describes the error. Int32 position The location in the parsed string that produced the ParseException Properties | Improve this Doc View Source Position The location in the parsed string that produced the ParseException . Declaration public int Position { get; } Property Value Type Description Int32 Methods | Improve this Doc View Source GetObjectData(SerializationInfo, StreamingContext) When overridden in a derived class, sets the SerializationInfo with information about the exception. Declaration public override void GetObjectData(SerializationInfo info, StreamingContext context) Parameters Type Name Description SerializationInfo info The SerializationInfo that holds the serialized object data about the exception being thrown. StreamingContext context The StreamingContext that contains contextual information about the source or destination. Overrides Exception.GetObjectData(SerializationInfo, StreamingContext) | Improve this Doc View Source ToString() Creates and returns a string representation of the current exception. Declaration public override string ToString() Returns Type Description String A string representation of the current exception. Overrides Exception.ToString() Implements System.Runtime.Serialization.ISerializable System.Runtime.InteropServices._Exception" }, - "api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html": { - "href": "api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html", - "title": "Class ExpressionParser", - "keywords": "Class ExpressionParser ExpressionParser Inheritance Object ExpressionParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public class ExpressionParser Constructors | Improve this Doc View Source ExpressionParser(ParameterExpression[], String, Object[], ParsingConfig) Initializes a new instance of the ExpressionParser class. Declaration public ExpressionParser([CanBeNull] ParameterExpression[] parameters, [NotNull] string expression, [CanBeNull] object[] values, [CanBeNull] ParsingConfig parsingConfig) Parameters Type Name Description ParameterExpression [] parameters The parameters. String expression The expression. Object [] values The values. ParsingConfig parsingConfig The parsing configuration. Properties | Improve this Doc View Source ItName Gets name for the it field. By default this is set to the KeyWord value \"it\". Declaration public string ItName { get; } Property Value Type Description String | Improve this Doc View Source LastLambdaItName There was a problem when an expression contained multiple lambdas where the ItName was not cleared and freed for the next lambda. This variable stores the ItName of the last parsed lambda. Not used internally by ExpressionParser, but used to preserve compatiblity of parsingConfig.RenameParameterExpression which was designed to only work with mono-lambda expressions. Declaration public string LastLambdaItName { get; } Property Value Type Description String Methods | Improve this Doc View Source Parse(Type, Boolean) Uses the TextParser to parse the string into the specified result type. Declaration public Expression Parse([CanBeNull] Type resultType, bool createParameterCtor = true) Parameters Type Name Description Type resultType Type of the result. Boolean createParameterCtor if set to true [create parameter ctor]. Returns Type Description Expression Expression" + "api/System.Linq.Dynamic.Core.ExtensibilityPoint.html": { + "href": "api/System.Linq.Dynamic.Core.ExtensibilityPoint.html", + "title": "Class ExtensibilityPoint", + "keywords": "Class ExtensibilityPoint Extensibility point: If you want to modify expanded queries before executing them set your own functionality to override empty QueryOptimizer Inheritance Object ExtensibilityPoint Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class ExtensibilityPoint Fields | Improve this Doc View Source QueryOptimizer Place to optimize your queries. Example: Add a reference to Nuget package Linq.Expression.Optimizer and in your program initializers set Extensibility.QueryOptimizer = ExpressionOptimizer.visit; Declaration public static Func QueryOptimizer Field Value Type Description Func < Expression , Expression >" }, - "api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html": { - "href": "api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html", - "title": "Interface IQueryableAnalyzer", - "keywords": "Interface IQueryableAnalyzer Interface for QueryableAnalyzer. Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IQueryableAnalyzer Methods | Improve this Doc View Source SupportsLinqToObjects(IQueryable, IQueryProvider) Determines whether the specified query (and provider) supports LinqToObjects. Declaration bool SupportsLinqToObjects([NotNull] IQueryable query, [CanBeNull] IQueryProvider provider = null) Parameters Type Name Description IQueryable query The query to check. IQueryProvider provider The provider to check (can be null). Returns Type Description Boolean true/false" + "api/System.Linq.Dynamic.Core.GroupResult.html": { + "href": "api/System.Linq.Dynamic.Core.GroupResult.html", + "title": "Class GroupResult", + "keywords": "Class GroupResult The result of a call to a DynamicQueryableExtensions .GroupByMany() overload. Inheritance Object GroupResult Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class GroupResult Properties | Improve this Doc View Source Count The number of resulting elements in the group. Declaration public int Count { get; } Property Value Type Description Int32 | Improve this Doc View Source Items The resulting elements in the group. Declaration public IEnumerable Items { get; } Property Value Type Description IEnumerable | Improve this Doc View Source Key The key value of the group. Declaration public object Key { get; } Property Value Type Description Object | Improve this Doc View Source Subgroups The resulting subgroups in the group. Declaration public IEnumerable Subgroups { get; } Property Value Type Description IEnumerable < GroupResult > Methods | Improve this Doc View Source ToString() Returns a String showing the key of the group and the number of items in the group. Declaration public override string ToString() Returns Type Description String A String that represents this instance. Overrides Object.ToString()" }, "api/System.Linq.Dynamic.Core.html": { "href": "api/System.Linq.Dynamic.Core.html", "title": "Namespace System.Linq.Dynamic.Core", "keywords": "Namespace System.Linq.Dynamic.Core Classes DefaultQueryableAnalyzer Default implementation. DynamicClass Provides a base class for dynamic objects for Net 3.5 DynamicClassFactory A factory to create dynamic classes, based on http://stackoverflow.com/questions/29413942/c-sharp-anonymous-object-with-properties-from-dictionary . DynamicEnumerableExtensions Define extensions on IEnumerable . DynamicExpressionParser Helper class to convert an expression into an LambdaExpression DynamicProperty DynamicProperty DynamicQueryableExtensions Provides a set of static (Shared in Visual Basic) methods for querying data structures that implement IQueryable . It allows dynamic string based querying. Very handy when, at compile time, you don't know the type of queries that will be generated, or when downstream components only return column names to sort and filter by. ExtensibilityPoint Extensibility point: If you want to modify expanded queries before executing them set your own functionality to override empty QueryOptimizer GroupResult The result of a call to a DynamicQueryableExtensions .GroupByMany() overload. PagedResult PagedResult PagedResult PagedResult{TSource} ParsingConfig Configuration class for System.Linq.Dynamic.Core. Interfaces IAssemblyHelper IAssemblyHelper interface which is used to retrieve assemblies that have been loaded into the execution context of this application domain. IQueryableAnalyzer Interface for QueryableAnalyzer." }, - "api/System.Linq.Dynamic.Core.Parser.NumberParser.html": { - "href": "api/System.Linq.Dynamic.Core.Parser.NumberParser.html", - "title": "Class NumberParser", - "keywords": "Class NumberParser NumberParser Inheritance Object NumberParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public class NumberParser Constructors | Improve this Doc View Source NumberParser(ParsingConfig) Initializes a new instance of the NumberParser class. Declaration public NumberParser(ParsingConfig config) Parameters Type Name Description ParsingConfig config The ParsingConfig. Methods | Improve this Doc View Source ParseNumber(String, Type) Parses the number (text) into the specified type. Declaration public object ParseNumber(string text, Type type) Parameters Type Name Description String text The text. Type type The type. Returns Type Description Object" + "api/System.Linq.Dynamic.Core.IAssemblyHelper.html": { + "href": "api/System.Linq.Dynamic.Core.IAssemblyHelper.html", + "title": "Interface IAssemblyHelper", + "keywords": "Interface IAssemblyHelper IAssemblyHelper interface which is used to retrieve assemblies that have been loaded into the execution context of this application domain. Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IAssemblyHelper Methods | Improve this Doc View Source GetAssemblies() Gets the assemblies that have been loaded into the execution context of this application domain. Declaration Assembly[] GetAssemblies() Returns Type Description Assembly [] An array of assemblies in this application domain." }, - "api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html": { - "href": "api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html", - "title": "Interface IExpressionPromoter", - "keywords": "Interface IExpressionPromoter Expression promoter is used to promote object or value types to their destination type when an automatic promotion is available such as: int to int? Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IExpressionPromoter Methods | Improve this Doc View Source Promote(Expression, Type, Boolean, Boolean) Promote an expression Declaration Expression Promote(Expression expr, Type type, bool exact, bool convertExpr) Parameters Type Name Description Expression expr Source expression Type type Destionation data type to promote Boolean exact If the match must be exact Boolean convertExpr Convert expression Returns Type Description Expression The promoted Expression" + "api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html": { + "href": "api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html", + "title": "Interface IQueryableAnalyzer", + "keywords": "Interface IQueryableAnalyzer Interface for QueryableAnalyzer. Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IQueryableAnalyzer Methods | Improve this Doc View Source SupportsLinqToObjects(IQueryable, IQueryProvider) Determines whether the specified query (and provider) supports LinqToObjects. Declaration bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null) Parameters Type Name Description IQueryable query The query to check. IQueryProvider provider The provider to check (can be null). Returns Type Description Boolean true/false" }, "api/System.Linq.Dynamic.Core.PagedResult.html": { "href": "api/System.Linq.Dynamic.Core.PagedResult.html", @@ -99,40 +114,60 @@ "title": "Class PagedResult", "keywords": "Class PagedResult PagedResult{TSource} Inheritance Object PagedResult PagedResult Inherited Members PagedResult.CurrentPage PagedResult.PageCount PagedResult.PageSize PagedResult.RowCount Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class PagedResult : PagedResult Type Parameters Name Description TSource The type of the source. Properties | Improve this Doc View Source Queryable Gets or sets the queryable. Declaration public IQueryable Queryable { get; set; } Property Value Type Description IQueryable The queryable." }, - "api/System.Linq.Dynamic.Core.GroupResult.html": { - "href": "api/System.Linq.Dynamic.Core.GroupResult.html", - "title": "Class GroupResult", - "keywords": "Class GroupResult The result of a call to a DynamicQueryableExtensions .GroupByMany() overload. Inheritance Object GroupResult Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class GroupResult Properties | Improve this Doc View Source Count The number of resulting elements in the group. Declaration public int Count { get; } Property Value Type Description Int32 | Improve this Doc View Source Items The resulting elements in the group. Declaration public IEnumerable Items { get; } Property Value Type Description IEnumerable | Improve this Doc View Source Key The key value of the group. Declaration public object Key { get; } Property Value Type Description Object | Improve this Doc View Source Subgroups The resulting subgroups in the group. Declaration public IEnumerable Subgroups { get; } Property Value Type Description IEnumerable < GroupResult > Methods | Improve this Doc View Source ToString() Returns a String showing the key of the group and the number of items in the group. Declaration public override string ToString() Returns Type Description String A String that represents this instance. Overrides Object.ToString()" - }, - "api/System.Linq.Dynamic.Core.ExtensibilityPoint.html": { - "href": "api/System.Linq.Dynamic.Core.ExtensibilityPoint.html", - "title": "Class ExtensibilityPoint", - "keywords": "Class ExtensibilityPoint Extensibility point: If you want to modify expanded queries before executing them set your own functionality to override empty QueryOptimizer Inheritance Object ExtensibilityPoint Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class ExtensibilityPoint Fields | Improve this Doc View Source QueryOptimizer Place to optimize your queries. Example: Add a reference to Nuget package Linq.Expression.Optimizer and in your program initializers set Extensibility.QueryOptimizer = ExpressionOptimizer.visit; Declaration public static Func QueryOptimizer Field Value Type Description Func < Expression , Expression >" + "api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html": { + "href": "api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html", + "title": "Class ExpressionParser", + "keywords": "Class ExpressionParser ExpressionParser Inheritance Object ExpressionParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public class ExpressionParser Constructors | Improve this Doc View Source ExpressionParser(ParameterExpression[], String, Object[], ParsingConfig) Initializes a new instance of the ExpressionParser class. Declaration public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, ParsingConfig parsingConfig) Parameters Type Name Description ParameterExpression [] parameters The parameters. String expression The expression. Object [] values The values. ParsingConfig parsingConfig The parsing configuration. Properties | Improve this Doc View Source ItName Gets name for the it field. By default this is set to the KeyWord value \"it\". Declaration public string ItName { get; } Property Value Type Description String | Improve this Doc View Source LastLambdaItName There was a problem when an expression contained multiple lambdas where the ItName was not cleared and freed for the next lambda. This variable stores the ItName of the last parsed lambda. Not used internally by ExpressionParser, but used to preserve compatiblity of parsingConfig.RenameParameterExpression which was designed to only work with mono-lambda expressions. Declaration public string LastLambdaItName { get; } Property Value Type Description String Methods | Improve this Doc View Source Parse(Type, Boolean) Uses the TextParser to parse the string into the specified result type. Declaration public Expression Parse(Type resultType, bool createParameterCtor = true) Parameters Type Name Description Type resultType Type of the result. Boolean createParameterCtor if set to true [create parameter ctor]. Returns Type Description Expression Expression" }, - "api/System.Linq.Dynamic.Core.Exceptions.ParseException.html": { - "href": "api/System.Linq.Dynamic.Core.Exceptions.ParseException.html", - "title": "Class ParseException", - "keywords": "Class ParseException Represents errors that occur while parsing dynamic linq string expressions. Inheritance Object Exception ParseException Implements ISerializable _Exception Inherited Members Exception.GetBaseException() Exception.GetType() Exception.Message Exception.Data Exception.InnerException Exception.TargetSite Exception.StackTrace Exception.HelpLink Exception.Source Exception.HResult Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Exceptions Assembly : System.Linq.Dynamic.Core.dll Syntax [Serializable] public sealed class ParseException : Exception, ISerializable, _Exception Constructors | Improve this Doc View Source ParseException(String, Int32) Initializes a new instance of the ParseException class with a specified error message and position. Declaration public ParseException(string message, int position) Parameters Type Name Description String message The message that describes the error. Int32 position The location in the parsed string that produced the ParseException Properties | Improve this Doc View Source Position The location in the parsed string that produced the ParseException . Declaration public int Position { get; } Property Value Type Description Int32 Methods | Improve this Doc View Source GetObjectData(SerializationInfo, StreamingContext) When overridden in a derived class, sets the SerializationInfo with information about the exception. Declaration public override void GetObjectData(SerializationInfo info, StreamingContext context) Parameters Type Name Description SerializationInfo info The SerializationInfo that holds the serialized object data about the exception being thrown. StreamingContext context The StreamingContext that contains contextual information about the source or destination. Overrides Exception.GetObjectData(SerializationInfo, StreamingContext) | Improve this Doc View Source ToString() Creates and returns a string representation of the current exception. Declaration public override string ToString() Returns Type Description String A string representation of the current exception. Overrides Exception.ToString() Implements System.Runtime.Serialization.ISerializable System.Runtime.InteropServices._Exception" + "api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html": { + "href": "api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html", + "title": "Class ExpressionPromoter", + "keywords": "Class ExpressionPromoter ExpressionPromoter Inheritance Object ExpressionPromoter Implements IExpressionPromoter Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public class ExpressionPromoter : IExpressionPromoter Constructors | Improve this Doc View Source ExpressionPromoter(ParsingConfig) Initializes a new instance of the ExpressionPromoter class. Declaration public ExpressionPromoter(ParsingConfig config) Parameters Type Name Description ParsingConfig config The ParsingConfig. Methods | Improve this Doc View Source Promote(Expression, Type, Boolean, Boolean) Promote an expression Declaration public virtual Expression Promote(Expression expr, Type type, bool exact, bool convertExpr) Parameters Type Name Description Expression expr Source expression Type type Destination data type to promote Boolean exact If the match must be exact Boolean convertExpr Convert expression Returns Type Description Expression The promoted Expression or null. Implements IExpressionPromoter" }, - "api/System.Linq.Dynamic.Core.DynamicProperty.html": { - "href": "api/System.Linq.Dynamic.Core.DynamicProperty.html", - "title": "Class DynamicProperty", - "keywords": "Class DynamicProperty DynamicProperty Inheritance Object DynamicProperty Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class DynamicProperty Constructors | Improve this Doc View Source DynamicProperty(String, Type) Initializes a new instance of the DynamicProperty class. Declaration public DynamicProperty(string name, Type type) Parameters Type Name Description String name The name from the property. Type type The type from the property. Properties | Improve this Doc View Source Name Gets the name from the property. Declaration public string Name { get; } Property Value Type Description String The name from the property. | Improve this Doc View Source Type Gets the type from the property. Declaration public Type Type { get; } Property Value Type Description Type The type from the property." + "api/System.Linq.Dynamic.Core.Parser.html": { + "href": "api/System.Linq.Dynamic.Core.Parser.html", + "title": "Namespace System.Linq.Dynamic.Core.Parser", + "keywords": "Namespace System.Linq.Dynamic.Core.Parser Classes ExpressionParser ExpressionParser ExpressionPromoter ExpressionPromoter NumberParser NumberParser Interfaces IExpressionPromoter Expression promoter is used to promote object or value types to their destination type when an automatic promotion is available such as: int to int?" }, - "api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html": { - "href": "api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html", - "title": "Class DynamicEnumerableExtensions", - "keywords": "Class DynamicEnumerableExtensions Define extensions on IEnumerable . Inheritance Object DynamicEnumerableExtensions Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicEnumerableExtensions Methods | Improve this Doc View Source ToDynamicArray(IEnumerable) Creates an array of dynamic objects from a IEnumerable . Declaration public static object[] ToDynamicArray([NotNull] this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description Object [] An array that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicArray(IEnumerable, Type) Creates an array of dynamic objects from a IEnumerable . Declaration public static object[] ToDynamicArray([NotNull] this IEnumerable source, [NotNull] Type type) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Type type A Type cast to. Returns Type Description Object [] An Array that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicArray(IEnumerable) Creates an array of dynamic objects from a IEnumerable . Declaration public static T[] ToDynamicArray([NotNull] this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description T[] An Array{T} that contains the elements from the input sequence. Type Parameters Name Description T The generic type. | Improve this Doc View Source ToDynamicList(IEnumerable) Creates a list of dynamic objects from a IEnumerable . Declaration public static List ToDynamicList([NotNull] this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description List < Object > A List that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicList(IEnumerable, Type) Creates a list of dynamic objects from a IEnumerable . Declaration public static List ToDynamicList([NotNull] this IEnumerable source, [NotNull] Type type) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Type type A Type cast to. Returns Type Description List < Object > A List that contains the elements from the input sequence. | Improve this Doc View Source ToDynamicList(IEnumerable) Creates a list of dynamic objects from a IEnumerable . Declaration public static List ToDynamicList([NotNull] this IEnumerable source) Parameters Type Name Description IEnumerable source A IEnumerable to create an array from. Returns Type Description List A List{T} that contains the elements from the input sequence. Type Parameters Name Description T Generic Type" + "api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html": { + "href": "api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html", + "title": "Interface IExpressionPromoter", + "keywords": "Interface IExpressionPromoter Expression promoter is used to promote object or value types to their destination type when an automatic promotion is available such as: int to int? Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public interface IExpressionPromoter Methods | Improve this Doc View Source Promote(Expression, Type, Boolean, Boolean) Promote an expression Declaration Expression Promote(Expression expr, Type type, bool exact, bool convertExpr) Parameters Type Name Description Expression expr Source expression Type type Destination data type to promote Boolean exact If the match must be exact Boolean convertExpr Convert expression Returns Type Description Expression The promoted Expression or null." }, - "api/System.Linq.Dynamic.Core.DynamicClassFactory.html": { - "href": "api/System.Linq.Dynamic.Core.DynamicClassFactory.html", - "title": "Class DynamicClassFactory", - "keywords": "Class DynamicClassFactory A factory to create dynamic classes, based on http://stackoverflow.com/questions/29413942/c-sharp-anonymous-object-with-properties-from-dictionary . Inheritance Object DynamicClassFactory Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public static class DynamicClassFactory Methods | Improve this Doc View Source CreateType(IList, Boolean) The CreateType method creates a new data class with a given set of public properties and returns the System.Type object for the newly created class. If a data class with an identical sequence of properties has already been created, the System.Type object for this class is returned. Data classes implement private instance variables and read/write property accessors for the specified properties.Data classes also override the Equals and GetHashCode members to implement by-value equality. Data classes are created in an in-memory assembly in the current application domain. All data classes inherit from DynamicClass and are given automatically generated names that should be considered private (the names will be unique within the application domain but not across multiple invocations of the application). Note that once created, a data class stays in memory for the lifetime of the current application domain. There is currently no way to unload a dynamically created data class. The dynamic expression parser uses the CreateClass methods to generate classes from data object initializers. This feature in turn is often used with the dynamic Select method to create projections. Declaration public static Type CreateType([NotNull] IList properties, bool createParameterCtor = true) Parameters Type Name Description IList < DynamicProperty > properties The DynamicProperties Boolean createParameterCtor Create a constructor with parameters. Default set to true. Note that for Linq-to-Database objects, this needs to be set to false. Returns Type Description Type Type Examples DynamicProperty[] props = new DynamicProperty[] { new DynamicProperty(\"Name\", typeof(string)), new DynamicProperty(\"Birthday\", typeof(DateTime)) }; Type type = DynamicClassFactory.CreateType(props); DynamicClass dynamicClass = Activator.CreateInstance(type) as DynamicClass; dynamicClass.SetDynamicProperty(\"Name\", \"Albert\"); dynamicClass.SetDynamicProperty(\"Birthday\", new DateTime(1879, 3, 14)); Console.WriteLine(dynamicClass);" + "api/System.Linq.Dynamic.Core.Parser.NumberParser.html": { + "href": "api/System.Linq.Dynamic.Core.Parser.NumberParser.html", + "title": "Class NumberParser", + "keywords": "Class NumberParser NumberParser Inheritance Object NumberParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Parser Assembly : System.Linq.Dynamic.Core.dll Syntax public class NumberParser Constructors | Improve this Doc View Source NumberParser(ParsingConfig) Initializes a new instance of the NumberParser class. Declaration public NumberParser(ParsingConfig config) Parameters Type Name Description ParsingConfig config The ParsingConfig. Methods | Improve this Doc View Source ParseIntegerLiteral(Int32, String) Tries to parse the text into a IntegerLiteral ConstantExpression. Declaration public Expression ParseIntegerLiteral(int tokenPosition, string text) Parameters Type Name Description Int32 tokenPosition The current token position (needed for error reporting). String text The text. Returns Type Description Expression | Improve this Doc View Source ParseNumber(String, Type) Parses the number (text) into the specified type. Declaration public object ParseNumber(string text, Type type) Parameters Type Name Description String text The text. Type type The type. Returns Type Description Object | Improve this Doc View Source ParseRealLiteral(String, Char, Boolean) Parse the text into a Real ConstantExpression. Declaration public Expression ParseRealLiteral(string text, char qualifier, bool stripQualifier) Parameters Type Name Description String text Char qualifier Boolean stripQualifier Returns Type Description Expression | Improve this Doc View Source TryParseNumber(String, Type, out Object) Tries to parse the number (text) into the specified type. Declaration public bool TryParseNumber(string text, Type type, out object result) Parameters Type Name Description String text The text. Type type The type. Object result The result. Returns Type Description Boolean" }, - "api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html": { - "href": "api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html", - "title": "Class DefaultQueryableAnalyzer", - "keywords": "Class DefaultQueryableAnalyzer Default implementation. Inheritance Object DefaultQueryableAnalyzer Implements IQueryableAnalyzer Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class DefaultQueryableAnalyzer : IQueryableAnalyzer Methods | Improve this Doc View Source SupportsLinqToObjects(IQueryable, IQueryProvider) Declaration public bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null) Parameters Type Name Description IQueryable query IQueryProvider provider Returns Type Description Boolean Implements IQueryableAnalyzer See Also IQueryableAnalyzer" + "api/System.Linq.Dynamic.Core.ParsingConfig.html": { + "href": "api/System.Linq.Dynamic.Core.ParsingConfig.html", + "title": "Class ParsingConfig", + "keywords": "Class ParsingConfig Configuration class for System.Linq.Dynamic.Core. Inheritance Object ParsingConfig Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core Assembly : System.Linq.Dynamic.Core.dll Syntax public class ParsingConfig Properties | Improve this Doc View Source AllowNewToEvaluateAnyType Allows the New() keyword to evaluate any available Type. Default value is false . Declaration public bool AllowNewToEvaluateAnyType { get; set; } Property Value Type Description Boolean | Improve this Doc View Source AreContextKeywordsEnabled Determines if the context keywords (it, parent, and root) are valid and usable inside a Dynamic Linq string expression. Does not affect the usability of the equivalent context symbols ($, ^ and ~). Default value is false . Declaration public bool AreContextKeywordsEnabled { get; set; } Property Value Type Description Boolean | Improve this Doc View Source CustomTypeProvider Gets or sets the IDynamicLinkCustomTypeProvider . Declaration public IDynamicLinkCustomTypeProvider CustomTypeProvider { get; set; } Property Value Type Description IDynamicLinkCustomTypeProvider | Improve this Doc View Source DateTimeIsParsedAsUTC By default DateTime (like 'Fri, 10 May 2019 11:03:17 GMT') is parsed as local time. Use this flag to parse all DateTime strings as UTC. Default value is false . Declaration public bool DateTimeIsParsedAsUTC { get; set; } Property Value Type Description Boolean | Improve this Doc View Source Default Default ParsingConfig Declaration public static ParsingConfig Default { get; } Property Value Type Description ParsingConfig | Improve this Doc View Source DefaultCosmosDb Default ParsingConfig for CosmosDb Declaration public static ParsingConfig DefaultCosmosDb { get; } Property Value Type Description ParsingConfig | Improve this Doc View Source DefaultEFCore21 Default ParsingConfig for EntityFramework Core 2.1 and higher Declaration public static ParsingConfig DefaultEFCore21 { get; } Property Value Type Description ParsingConfig | Improve this Doc View Source DisableMemberAccessToIndexAccessorFallback By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use this flag to disable this behaviour and have parsing fail when parsing an expression where a member access on a non existing member happens. Default value is false . Declaration public bool DisableMemberAccessToIndexAccessorFallback { get; set; } Property Value Type Description Boolean | Improve this Doc View Source EvaluateGroupByAtDatabase Gets or sets a value indicating whether the EntityFramework version supports evaluating GroupBy at database level. See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1#linq-groupby-translation Remark: when this setting is set to 'true', make sure to supply this ParsingConfig as first parameter on the extension methods. Default value is false . Declaration public bool EvaluateGroupByAtDatabase { get; set; } Property Value Type Description Boolean | Improve this Doc View Source ExpressionPromoter Gets or sets the IExpressionPromoter . Declaration public IExpressionPromoter ExpressionPromoter { get; set; } Property Value Type Description IExpressionPromoter | Improve this Doc View Source IsCaseSensitive Gets or sets if parameter, method, and properties resolution should be case sensitive or not (false by default). Declaration public bool IsCaseSensitive { get; set; } Property Value Type Description Boolean | Improve this Doc View Source NullPropagatingUseDefaultValueForNonNullableValueTypes When using the NullPropagating function np(...), use a \"default value\" for non-nullable value types instead of \"null value\". Default value is false . Declaration public bool NullPropagatingUseDefaultValueForNonNullableValueTypes { get; set; } Property Value Type Description Boolean | Improve this Doc View Source NumberParseCulture The number parsing culture. Default value is CultureInfo.InvariantCulture Declaration public CultureInfo NumberParseCulture { get; set; } Property Value Type Description CultureInfo | Improve this Doc View Source PrioritizePropertyOrFieldOverTheType When the type and property have the same name the parser takes the property instead of type when this setting is set to true . This setting is also used for calling ExtensionMethods. Default value is true . Declaration public bool PrioritizePropertyOrFieldOverTheType { get; set; } Property Value Type Description Boolean | Improve this Doc View Source QueryableAnalyzer Gets or sets the IQueryableAnalyzer . Declaration public IQueryableAnalyzer QueryableAnalyzer { get; set; } Property Value Type Description IQueryableAnalyzer | Improve this Doc View Source RenameEmptyParameterExpressionNames Prevents any System.Linq.Expressions.ParameterExpression.Name value from being empty by substituting a random 16 character word. Default value is false . Declaration public bool RenameEmptyParameterExpressionNames { get; set; } Property Value Type Description Boolean | Improve this Doc View Source RenameParameterExpression Renames the (Typed)ParameterExpression empty Name to a the correct supplied name from it . Default value is false . Declaration public bool RenameParameterExpression { get; set; } Property Value Type Description Boolean | Improve this Doc View Source ResolveTypesBySimpleName By default finding types by a simple name is not supported. Use this flag to use the CustomTypeProvider to resolve types by a simple name like \"Employee\" instead of \"MyDatabase.Entities.Employee\". Note that a first matching type is returned and this functionality needs to scan all types from all assemblies, so use with caution. Default value is false . Declaration public bool ResolveTypesBySimpleName { get; set; } Property Value Type Description Boolean | Improve this Doc View Source SupportCastingToFullyQualifiedTypeAsString Support casting to a full qualified type using a string (double quoted value). var result = queryable.Select($\"\\\"System.DateTime\\\"(LastUpdate)\"); Default value is true . Declaration public bool SupportCastingToFullyQualifiedTypeAsString { get; set; } Property Value Type Description Boolean | Improve this Doc View Source SupportEnumerationsFromSystemNamespace Support enumeration-types from the System namespace in mscorlib. An example could be \"StringComparison\". Default value is true. Declaration public bool SupportEnumerationsFromSystemNamespace { get; set; } Property Value Type Description Boolean | Improve this Doc View Source TypeConverters Additional TypeConverters Declaration public IDictionary TypeConverters { get; set; } Property Value Type Description IDictionary < Type , TypeConverter > | Improve this Doc View Source UseParameterizedNamesInDynamicQuery Use Parameterized Names in generated dynamic SQL query. See https://github.com/graeme-hill/gblog/blob/master/source_content/articles/2014.139_entity-framework-dynamic-queries-and-parameterization.mkd Default value is false . Declaration public bool UseParameterizedNamesInDynamicQuery { get; set; } Property Value Type Description Boolean" + }, + "api/System.Linq.Dynamic.Core.Tokenizer.html": { + "href": "api/System.Linq.Dynamic.Core.Tokenizer.html", + "title": "Namespace System.Linq.Dynamic.Core.Tokenizer", + "keywords": "Namespace System.Linq.Dynamic.Core.Tokenizer Classes TextParser TextParser which can be used to parse a text into tokens. Structs Token Token Enums TokenId TokenId which defines the text which is parsed." + }, + "api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html": { + "href": "api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html", + "title": "Class TextParser", + "keywords": "Class TextParser TextParser which can be used to parse a text into tokens. Inheritance Object TextParser Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System.Linq.Dynamic.Core.Tokenizer Assembly : System.Linq.Dynamic.Core.dll Syntax public class TextParser Constructors | Improve this Doc View Source TextParser(ParsingConfig, String) Constructor for TextParser Declaration public TextParser(ParsingConfig config, string text) Parameters Type Name Description ParsingConfig config String text Fields | Improve this Doc View Source CurrentToken The current parsed Token . Declaration public Token CurrentToken Field Value Type Description Token Methods | Improve this Doc View Source NextToken() Go to the next token. Declaration public void NextToken() | Improve this Doc View Source PeekNextChar() Peek the next character. Declaration public char PeekNextChar() Returns Type Description Char The next character, or \\0 if end of string. | Improve this Doc View Source ValidateToken(TokenId, String) Check if the current token is the specified TokenId . Declaration public void ValidateToken(TokenId tokenId, string errorMessage = null) Parameters Type Name Description TokenId tokenId The tokenId to check. String errorMessage The (optional) error message." + }, + "api/System.Linq.Dynamic.Core.Tokenizer.Token.html": { + "href": "api/System.Linq.Dynamic.Core.Tokenizer.Token.html", + "title": "Struct Token", + "keywords": "Struct Token Token Inherited Members ValueType.Equals(Object) ValueType.GetHashCode() ValueType.ToString() Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetType() Namespace : System.Linq.Dynamic.Core.Tokenizer Assembly : System.Linq.Dynamic.Core.dll Syntax public struct Token Properties | Improve this Doc View Source Id The TokenId. Declaration public TokenId Id { readonly get; set; } Property Value Type Description TokenId | Improve this Doc View Source OriginalId The Original TokenId. Declaration public TokenId OriginalId { readonly get; set; } Property Value Type Description TokenId | Improve this Doc View Source Pos The position. Declaration public int Pos { readonly get; set; } Property Value Type Description Int32 | Improve this Doc View Source Text The text. Declaration public string Text { readonly get; set; } Property Value Type Description String" + }, + "api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html": { + "href": "api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html", + "title": "Enum TokenId", + "keywords": "Enum TokenId TokenId which defines the text which is parsed. Namespace : System.Linq.Dynamic.Core.Tokenizer Assembly : System.Linq.Dynamic.Core.dll Syntax public enum TokenId Fields Name Description Ampersand Asterisk Bar CloseBracket CloseCurlyParen CloseParen Colon Comma Dot DoubleAmpersand DoubleBar DoubleEqual DoubleGreaterThan DoubleLessThan End Equal Exclamation ExclamationEqual GreaterThan GreaterThanEqual Identifier IntegerLiteral Lambda LessGreater LessThan LessThanEqual Minus NullCoalescing NullPropagation OpenBracket OpenCurlyParen OpenParen Percent Plus Question RealLiteral Slash StringLiteral Unknown" + }, + "api/System.Tuple-2.html": { + "href": "api/System.Tuple-2.html", + "title": "Class Tuple", + "keywords": "Class Tuple Represents a 2-tuple, or pair. Inheritance Object Tuple Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : System Assembly : System.Linq.Dynamic.Core.dll Syntax public class Tuple Type Parameters Name Description T1 The type of the tuple's first component. T2 The type of the tuple's second component. Properties | Improve this Doc View Source Item1 The value of the current System.Tuple`2 object's first component. Declaration public T1 Item1 { get; } Property Value Type Description T1 | Improve this Doc View Source Item2 The value of the current System.Tuple`2 object's second component. Declaration public T2 Item2 { get; } Property Value Type Description T2" }, "index.html": { "href": "index.html", diff --git a/docs/manifest.json b/docs/manifest.json index 964186c8..111ec7e7 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1,6 +1,6 @@ { "homepages": [], - "source_base_path": "C:/Users/azurestef/Documents/Github/System.Linq.Dynamic.Core/docfx", + "source_base_path": "C:/Dev/GitHub/System.Linq.Dynamic.Core/docfx", "xrefmap": "xrefmap.yml", "files": [ { @@ -21,7 +21,7 @@ "output": { ".html": { "relative_path": "index.html", - "hash": "S3NHAAk85Ok7eYFcHW+YSA==" + "hash": "uaaLuzHOGOpYFTOWMJwzcdPUAQQfuWt6w+BGfTFcuB8=" } }, "is_incremental": false, @@ -33,7 +33,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.CustomTypeProviders.AbstractDynamicLinqCustomTypeProvider.html", - "hash": "9rxSx4b0SBVqwFOHzM0G2g==" + "hash": "Hw4zaHuWpQD3BQ5RFW8FxSPTPZwDwmTIOp829oJVVgA=" } }, "is_incremental": false, @@ -45,7 +45,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.CustomTypeProviders.DefaultDynamicLinqCustomTypeProvider.html", - "hash": "2fAGsIyojlwnfsqZseUq3A==" + "hash": "tOjhiA9SOysNhX9225GNgSgqw7XHztu3/AWcn55tKyI=" } }, "is_incremental": false, @@ -57,7 +57,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.CustomTypeProviders.DynamicLinqTypeAttribute.html", - "hash": "w9I9TjnlGb9PVNHDIBk64A==" + "hash": "krSzJhQDPcuUnnL2dcqHg144x18g7BDQ47mukGi5jiY=" } }, "is_incremental": false, @@ -69,7 +69,19 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinkCustomTypeProvider.html", - "hash": "BjzsbaY/q+ZL/KmIe2ahPQ==" + "hash": "pktG3uZIbOdmUSdBxJoOAFn9ZOOzFygvoHpbacgcy4k=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.yml", + "output": { + ".html": { + "relative_path": "api/System.Linq.Dynamic.Core.CustomTypeProviders.IDynamicLinqCustomTypeProvider.html", + "hash": "8NayIEt7xA6QnbgZOunViYnTqd/K1xE5LOV38KhKd00=" } }, "is_incremental": false, @@ -81,7 +93,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.CustomTypeProviders.html", - "hash": "Au76FiUAjfJ3F1xE849rSw==" + "hash": "PzsyUBS7aDF/GhmvAHSKEdIFX1uSUL/Gn+WN6PFuzgo=" } }, "is_incremental": false, @@ -93,7 +105,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DefaultQueryableAnalyzer.html", - "hash": "Kez9WcD02j+PSPnIy7y7mw==" + "hash": "9SP4P0EhLif7BBemSeTWOlA3eJFW67Mzh7grTGWrhdg=" } }, "is_incremental": false, @@ -105,7 +117,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DynamicClass.html", - "hash": "K2YnelOyPP9cBuLQRLNvXw==" + "hash": "dv7dn53UdvS2xxNnXoqwiKEqcN5Vmp5JrWjoMmfGZwg=" } }, "is_incremental": false, @@ -117,7 +129,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DynamicClassFactory.html", - "hash": "hqgCDHmY/o8vqtBZP/m2+g==" + "hash": "Cpdy7iQz+xFy/UQiAYW+LJoAKTN1G3naQVDnYB1Fa8E=" } }, "is_incremental": false, @@ -129,7 +141,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DynamicEnumerableExtensions.html", - "hash": "am0BtlfBBq0ZZa9AlH7kkQ==" + "hash": "AFND/nPjfatcn6h4XxbRGj2WxMAM7TsPPVFXSb6nMdo=" } }, "is_incremental": false, @@ -141,7 +153,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DynamicExpressionParser.html", - "hash": "d0cTw+u9ELG8WIoc8yTAew==" + "hash": "tsWJlTcTZohalud1TpEGshzVQa6W4znROuaoM/r5vW4=" } }, "is_incremental": false, @@ -153,7 +165,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DynamicProperty.html", - "hash": "ut1VqHn7yaRTo4JAWmEBoA==" + "hash": "kRcJfsqYptA+g3He8TIKUTxWr6fu4ThncePPqZhMI3U=" } }, "is_incremental": false, @@ -165,7 +177,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.DynamicQueryableExtensions.html", - "hash": "Q1kwBq4xA8pAw7rLEPtJNw==" + "hash": "8Scsef33jXhnfUNwgNkLf9pDMpixu4qWOHe3r+SzaDc=" } }, "is_incremental": false, @@ -177,7 +189,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Exceptions.ParseException.html", - "hash": "VVMqUE6zrSb7Xdm/eRS2QA==" + "hash": "JwvstWZuhLt+QjCE3HWqVzd/vZe13sB1aU7gq1tf1YE=" } }, "is_incremental": false, @@ -189,7 +201,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Exceptions.html", - "hash": "sEUt1uZ8yHZ2uC83z+XQ7g==" + "hash": "TMZDhUexjQ4NuDc6TKT4amBbysRPqQQrYNdXISr78pE=" } }, "is_incremental": false, @@ -201,7 +213,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.ExtensibilityPoint.html", - "hash": "VNDZW+Iwq5Y3RadxZMaLJA==" + "hash": "63G/lgWlz6103fZkAyP1LFejWM02Yg4arDEqkfBgCis=" } }, "is_incremental": false, @@ -213,7 +225,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.GroupResult.html", - "hash": "up4m32Lm4CMn+52PV9HlGw==" + "hash": "FyTflxv9BjDM5qFUpGj5ofiCtFnPgVt9NLiscACGNLo=" } }, "is_incremental": false, @@ -225,7 +237,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.IAssemblyHelper.html", - "hash": "6cuddGrMlc/K/c4N5Op6ng==" + "hash": "0lMGOtbSDLIxq75I0DpK5hVBEmWUrWy33/s2gMh4APE=" } }, "is_incremental": false, @@ -237,7 +249,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.IQueryableAnalyzer.html", - "hash": "4R48JsE0uI0BfTIu8WqrGw==" + "hash": "PVK2ufWtA8znWYt/j/JEQPDWdhOzPXWj7cX6i2yBpz8=" } }, "is_incremental": false, @@ -249,7 +261,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.PagedResult-1.html", - "hash": "mG5JvSNbQdQDTCOo7vVyvA==" + "hash": "vpwnq+ZSNsWsmRm5JEdiWdg0JiA8gwkCjAdGtSVideA=" } }, "is_incremental": false, @@ -261,7 +273,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.PagedResult.html", - "hash": "2rPFdEaPVbq3rMrYTKgJlA==" + "hash": "iFARffOWfmiDv6G1QWduT1EdDBVY/AOvIeUBKWnDuiA=" } }, "is_incremental": false, @@ -273,7 +285,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Parser.ExpressionParser.html", - "hash": "Q/Dk+zOcTzWMkYvrqXOrMg==" + "hash": "E0V6UOejA9k9JpCTVILhcDT3NyJEXW5mPKoNlpIvPqM=" } }, "is_incremental": false, @@ -285,7 +297,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Parser.ExpressionPromoter.html", - "hash": "JAnL/C5Odv80CvqvSPoxKQ==" + "hash": "4M+SGT8CBEEVLMse+NH7XP5SGxOn7bFnyYTUIp7YI1o=" } }, "is_incremental": false, @@ -297,7 +309,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Parser.IExpressionPromoter.html", - "hash": "MmGht9ji/Ua7537NTIGqRA==" + "hash": "YAr5s5r1GdnKDMDA6eUvLjQQsA/3SWxzdA9KmKGN0ew=" } }, "is_incremental": false, @@ -309,7 +321,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Parser.NumberParser.html", - "hash": "z1psm/vcnDS0RrRe9EeS8g==" + "hash": "UCU88Y0WQV7xmdA5pA4fPVNBbD4XNfMpBdSXQ7172Yc=" } }, "is_incremental": false, @@ -321,7 +333,7 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.Parser.html", - "hash": "dOPqplm+EX8q1ajrbwNfJA==" + "hash": "b6Ny3COTtys70rPFSpwCHnMdZkmwYWxRTIQ3EgpkX5w=" } }, "is_incremental": false, @@ -333,7 +345,55 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.ParsingConfig.html", - "hash": "RLtuyetrON7rS6Uc3sRjbg==" + "hash": "cfAv4clBBdg+P6NKJaZBzjeNeR3SHHeUUlZbgfC02XM=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.Linq.Dynamic.Core.Tokenizer.TextParser.yml", + "output": { + ".html": { + "relative_path": "api/System.Linq.Dynamic.Core.Tokenizer.TextParser.html", + "hash": "Cxz2FiBBqCS4FYsKBLKiJwZ/Hbpfdiw+jN3fY2ncrkY=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.Linq.Dynamic.Core.Tokenizer.Token.yml", + "output": { + ".html": { + "relative_path": "api/System.Linq.Dynamic.Core.Tokenizer.Token.html", + "hash": "Ky7+SPEfzi85NZPPzdRelr4g85kdizPOYaGQy/3zucg=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.Linq.Dynamic.Core.Tokenizer.TokenId.yml", + "output": { + ".html": { + "relative_path": "api/System.Linq.Dynamic.Core.Tokenizer.TokenId.html", + "hash": "RqploYlaA/pJMNTovH5CH0PMoAP4d2ZipVwl1A9g8go=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.Linq.Dynamic.Core.Tokenizer.yml", + "output": { + ".html": { + "relative_path": "api/System.Linq.Dynamic.Core.Tokenizer.html", + "hash": "qToFeeIFGY5Vj9ayURfZCFDrO6P9kU9ilQ7+2MRuO/w=" } }, "is_incremental": false, @@ -345,7 +405,31 @@ "output": { ".html": { "relative_path": "api/System.Linq.Dynamic.Core.html", - "hash": "w93UFiUkTKo0T+vyialC8A==" + "hash": "BZbu11MilL0q2XoH7x4QiBg0S34mgG3eRGD8YTki218=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.Tuple-2.yml", + "output": { + ".html": { + "relative_path": "api/System.Tuple-2.html", + "hash": "/bhh59QFEoVJTihGiRaDZx3kjJpY+ON8nVOAlDeESjM=" + } + }, + "is_incremental": false, + "version": "" + }, + { + "type": "ManagedReference", + "source_relative_path": "obj/api/System.yml", + "output": { + ".html": { + "relative_path": "api/System.html", + "hash": "Vo7N+h54VKYN5S/uuiphiQXEeWCe4hlZ5MUNZza8Y80=" } }, "is_incremental": false, @@ -357,7 +441,7 @@ "output": { ".html": { "relative_path": "api/toc.html", - "hash": "fIJKSZpkXuHrnhchcTsu/g==" + "hash": "PUzKU9mY6/vUK2w0WoNh7stbaXsjL5stoxCxUUbR56E=" } }, "is_incremental": false, @@ -369,7 +453,7 @@ "output": { ".html": { "relative_path": "toc.html", - "hash": "pz2m69lBFGpGVLYPhrwsww==" + "hash": "AhmODiRx3iAoACeoo5HPzXB8ykYpJ/ZaRUvXCLXoIXY=" } }, "is_incremental": false, @@ -389,13 +473,13 @@ "can_incremental": true, "incrementalPhase": "build", "total_file_count": 1, - "skipped_file_count": 0 + "skipped_file_count": 1 }, "ManagedReferenceDocumentProcessor": { "can_incremental": true, "incrementalPhase": "build", - "total_file_count": 27, - "skipped_file_count": 27 + "total_file_count": 34, + "skipped_file_count": 34 }, "TocDocumentProcessor": { "can_incremental": false, diff --git a/docs/styles/docfx.css b/docs/styles/docfx.css index dc00b040..64dcde33 100644 --- a/docs/styles/docfx.css +++ b/docs/styles/docfx.css @@ -42,7 +42,11 @@ h6 mark { .inheritance .level2:before, .inheritance .level3:before, .inheritance .level4:before, -.inheritance .level5:before { +.inheritance .level5:before, +.inheritance .level6:before, +.inheritance .level7:before, +.inheritance .level8:before, +.inheritance .level9:before { content: '↳'; margin-right: 5px; } @@ -71,6 +75,30 @@ h6 mark { margin-left: 5em; } +.inheritance .level6 { + margin-left: 6em; +} + +.inheritance .level7 { + margin-left: 7em; +} + +.inheritance .level8 { + margin-left: 8em; +} + +.inheritance .level9 { + margin-left: 9em; +} + +.level0.summary { + margin: 2em 0 2em 0; +} + +.level1.summary { + margin: 1em 0 1em 0; +} + span.parametername, span.paramref, span.typeparamref { @@ -194,7 +222,9 @@ article h1, article h2, article h3, article h4{ } article h4{ - border-bottom: 1px solid #ccc; + border: 0; + font-weight: bold; + margin-top: 2em; } article span.small.pull-right{ @@ -843,6 +873,33 @@ footer { } } +/* Code snippet */ +code { + color: #717374; + background-color: #f1f2f3; +} + +a code { + color: #337ab7; + background-color: #f1f2f3; +} + +a code:hover { + text-decoration: underline; +} + +.hljs-keyword { + color: rgb(86,156,214); +} + +.hljs-string { + color: rgb(214, 157, 133); +} + +pre { + border: 0; +} + /* For code snippet line highlight */ pre > code .line-highlight { background-color: #ffffcc; @@ -960,3 +1017,16 @@ div.embeddedvideo iframe { .mainContainer[dir='rtl'] main ul[role="tablist"] { margin: 0; } + +/* Color theme */ + +/* These are not important, tune down **/ +.decalaration, .fieldValue, .parameters, .returns { + color: #a2a2a2; +} + +/* Major sections, increase visibility **/ +#fields, #properties, #methods, #events { + font-weight: bold; + margin-top: 2em; +} diff --git a/docs/styles/docfx.js b/docs/styles/docfx.js index 384396b3..04b4baed 100644 --- a/docs/styles/docfx.js +++ b/docs/styles/docfx.js @@ -65,7 +65,7 @@ $(function () { (function () { anchors.options = { placement: 'left', - visible: 'touch' + visible: 'hover' }; anchors.add('article h2:not(.no-anchor), article h3:not(.no-anchor), article h4:not(.no-anchor)'); })(); @@ -232,7 +232,7 @@ $(function () { // Highlight the searching keywords function highlightKeywords() { var q = url('?q'); - if (q !== null) { + if (q) { var keywords = q.split("%20"); keywords.forEach(function (keyword) { if (keyword !== "") { @@ -256,7 +256,7 @@ $(function () { } else { flipContents("hide"); $("body").trigger("queryReady"); - $('#search-results>.search-list').text('Search Results for "' + query + '"'); + $('#search-results>.search-list>span').text('"' + query + '"'); } }).off("keydown"); }); @@ -301,12 +301,17 @@ $(function () { function handleSearchResults(hits) { var numPerPage = 10; - $('#pagination').empty(); - $('#pagination').removeData("twbs-pagination"); + var pagination = $('#pagination'); + pagination.empty(); + pagination.removeData("twbs-pagination"); if (hits.length === 0) { $('#search-results>.sr-items').html('

                                                                                                                                No results found

                                                                                                                                '); - } else { - $('#pagination').twbsPagination({ + } else { + pagination.twbsPagination({ + first: pagination.data('first'), + prev: pagination.data('prev'), + next: pagination.data('next'), + last: pagination.data('last'), totalPages: Math.ceil(hits.length / numPerPage), visiblePages: 5, onPageClick: function (event, page) { @@ -321,7 +326,7 @@ $(function () { var itemBrief = extractContentBrief(hit.keywords); var itemNode = $('
                                                                                                                                ').attr('class', 'sr-item'); - var itemTitleNode = $('
                                                                                                                                ').attr('class', 'item-title').append($('').attr('href', itemHref).attr("target", "_blank").text(itemTitle)); + var itemTitleNode = $('
                                                                                                                                ').attr('class', 'item-title').append($('').attr('href', itemHref).attr("target", "_blank").attr("rel", "noopener noreferrer").text(itemTitle)); var itemHrefNode = $('
                                                                                                                                ').attr('class', 'item-href').text(itemRawHref); var itemBriefNode = $('
                                                                                                                                ').attr('class', 'item-brief').text(itemBrief); itemNode.append(itemTitleNode).append(itemHrefNode).append(itemBriefNode); @@ -374,7 +379,7 @@ $(function () { navrel = navbarPath.substr(0, index + 1); } $('#navbar>ul').addClass('navbar-nav'); - var currentAbsPath = util.getAbsolutePath(window.location.pathname); + var currentAbsPath = util.getCurrentWindowAbsolutePath(); // set active item $('#navbar').find('a[href]').each(function (i, e) { var href = $(e).attr("href"); @@ -422,6 +427,8 @@ $(function () { $('#toc a.active').parents('li').each(function (i, e) { $(e).addClass(active).addClass(expanded); $(e).children('a').addClass(active); + }) + $('#toc a.active').parents('li').each(function (i, e) { top += $(e).position().top; }) $('.sidetoc').scrollTop(top - 50); @@ -447,7 +454,11 @@ $(function () { var val = this.value; //Save filter string to local session storage if (typeof(Storage) !== "undefined") { - sessionStorage.filterString = val; + try { + sessionStorage.filterString = val; + } + catch(e) + {} } if (val === '') { // Clear 'filtered' class @@ -456,6 +467,16 @@ $(function () { return; } tocFilterClearButton.fadeIn(); + + // set all parent nodes status + $('#toc li>a').filter(function (i, e) { + return $(e).siblings().length > 0 + }).each(function (i, anchor) { + var parent = $(anchor).parent(); + parent.addClass(hide); + parent.removeClass(show); + parent.removeClass(filtered); + }) // Get leaf nodes $('#toc li>a').filter(function (i, e) { @@ -504,14 +525,22 @@ $(function () { tocFilterInput.val(""); tocFilterInput.trigger('input'); if (typeof(Storage) !== "undefined") { - sessionStorage.filterString = ""; + try { + sessionStorage.filterString = ""; + } + catch(e) + {} } }); //Set toc filter from local session storage on page load if (typeof(Storage) !== "undefined") { - tocFilterInput.val(sessionStorage.filterString); - tocFilterInput.trigger('input'); + try { + tocFilterInput.val(sessionStorage.filterString); + tocFilterInput.trigger('input'); + } + catch(e) + {} } } @@ -527,7 +556,10 @@ $(function () { if (index > -1) { tocrel = tocPath.substr(0, index + 1); } - var currentHref = util.getAbsolutePath(window.location.pathname); + var currentHref = util.getCurrentWindowAbsolutePath(); + if(!currentHref.endsWith('.html')) { + currentHref += '.html'; + } $('#sidetoc').find('a[href]').each(function (i, e) { var href = $(e).attr("href"); if (util.isRelativePath(href)) { @@ -569,10 +601,12 @@ $(function () { //Setup Affix function renderAffix() { var hierarchy = getHierarchy(); - if (hierarchy && hierarchy.length > 0) { - var html = '
                                                                                                                                In This Article
                                                                                                                                ' - html += util.formList(hierarchy, ['nav', 'bs-docs-sidenav']); - $("#affix").empty().append(html); + if (!hierarchy || hierarchy.length <= 0) { + $("#affix").hide(); + } + else { + var html = util.formList(hierarchy, ['nav', 'bs-docs-sidenav']); + $("#affix>div").empty().append(html); if ($('footer').is(':visible')) { $(".sideaffix").css("bottom", "70px"); } @@ -956,7 +990,7 @@ $(function () { } function readTabsQueryStringParam() { - var qs = parseQueryString(); + var qs = parseQueryString(window.location.search); var t = qs.tabs; if (t === undefined || t === '') { return []; @@ -965,7 +999,7 @@ $(function () { } function updateTabsQueryStringParam(state) { - var qs = parseQueryString(); + var qs = parseQueryString(window.location.search); qs.tabs = state.selectedTabs.join(); var url = location.protocol + "//" + location.host + location.pathname + "?" + toQueryString(qs) + location.hash; if (location.href === url) { @@ -1023,14 +1057,25 @@ $(function () { this.getAbsolutePath = getAbsolutePath; this.isRelativePath = isRelativePath; this.isAbsolutePath = isAbsolutePath; + this.getCurrentWindowAbsolutePath = getCurrentWindowAbsolutePath; this.getDirectory = getDirectory; this.formList = formList; function getAbsolutePath(href) { - // Use anchor to normalize href - var anchor = $('
                                                                                                                                ')[0]; - // Ignore protocal, remove search and query - return anchor.host + anchor.pathname; + if (isAbsolutePath(href)) return href; + var currentAbsPath = getCurrentWindowAbsolutePath(); + var stack = currentAbsPath.split("/"); + stack.pop(); + var parts = href.split("/"); + for (var i=0; i< parts.length; i++) { + if (parts[i] == ".") continue; + if (parts[i] == ".." && stack.length > 0) + stack.pop(); + else + stack.push(parts[i]); + } + var p = stack.join("/"); + return p; } function isRelativePath(href) { @@ -1044,6 +1089,9 @@ $(function () { return (/^(?:[a-z]+:)?\/\//i).test(href); } + function getCurrentWindowAbsolutePath() { + return window.location.origin + window.location.pathname; + } function getDirectory(href) { if (!href) return ''; var index = href.lastIndexOf('/'); @@ -1162,7 +1210,7 @@ $(function () { $(window).on('hashchange', scrollToCurrent); - $(window).load(function () { + $(window).on('load', function () { // scroll to the anchor if present, offset by the header scrollToCurrent(); }); diff --git a/docs/styles/docfx.vendor.css b/docs/styles/docfx.vendor.css index 91bb610c..609602eb 100644 --- a/docs/styles/docfx.vendor.css +++ b/docs/styles/docfx.vendor.css @@ -1,54 +1,50 @@ /*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ -.label,sub,sup{vertical-align:baseline} -hr,img{border:0} -body,figure{margin:0} -.btn-group>.btn-group,.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.dropdown-menu{float:left} -.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px} -html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%} +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block} audio,canvas,progress,video{display:inline-block;vertical-align:baseline} audio:not([controls]){display:none;height:0} [hidden],template{display:none} -a{background-color:transparent} a:active,a:hover{outline:0} +abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;text-decoration:underline dotted} b,optgroup,strong{font-weight:700} dfn{font-style:italic} h1{margin:.67em 0} -mark{color:#000;background:#ff0} -sub,sup{position:relative;font-size:75%;line-height:0} +mark{background:#ff0;color:#000} +sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} sup{top:-.5em} sub{bottom:-.25em} -img{vertical-align:middle} +img{border:0;vertical-align:middle} svg:not(:root){overflow:hidden} -hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} -pre,textarea{overflow:auto} +hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0} code,kbd,pre,samp{font-size:1em} -button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit} -.glyphicon,address{font-style:normal} +button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0} button{overflow:visible} button,select{text-transform:none} button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} -button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0} +button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} +input{line-height:normal} input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0} input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto} +input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none} -table{border-spacing:0;border-collapse:collapse} +textarea{overflow:auto} td,th{padding:0} /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print{blockquote,img,pre,tr{page-break-inside:avoid} +@media print{ *,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} -a[href^="javascript:"]:after,a[href^="#"]:after{content:""} -blockquote,pre{border:1px solid #999} +a[href^="#"]:after,a[href^="javascript:"]:after{content:""} +blockquote,pre{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} +img,tr{page-break-inside:avoid} img{max-width:100%!important} h2,h3,p{orphans:3;widows:3} h2,h3{page-break-after:avoid} @@ -59,11 +55,8 @@ h2,h3{page-break-after:avoid} .table td,.table th{background-color:#fff!important} .table-bordered td,.table-bordered th{border:1px solid #ddd!important} } -.dropdown-menu,.modal-content{-webkit-background-clip:padding-box} -.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none} -.img-thumbnail,body{background-color:#fff} -@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')} -.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} +@font-face{font-family:"Glyphicons Halflings";src:url("../fonts/glyphicons-halflings-regular.eot");src:url("../fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/glyphicons-halflings-regular.woff2") format("woff2"),url("../fonts/glyphicons-halflings-regular.woff") format("woff"),url("../fonts/glyphicons-halflings-regular.ttf") format("truetype"),url("../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg")} +.glyphicon{position:relative;top:1px;display:inline-block;font-family:"Glyphicons Halflings";font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} .glyphicon-asterisk:before{content:"\002a"} .glyphicon-plus:before{content:"\002b"} .glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"} @@ -324,16 +317,17 @@ h2,h3{page-break-after:avoid} .glyphicon-menu-up:before{content:"\e260"} *,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} html{font-size:10px;-webkit-tap-highlight-color:transparent} -body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333} +body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff} button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit} -a{color:#337ab7;text-decoration:none} +a{background-color:transparent;color:#337ab7;text-decoration:none} a:focus,a:hover{color:#23527c;text-decoration:underline} a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +figure{margin:0} .carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto} .img-rounded{border-radius:6px} -.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out} +.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:.2s ease-in-out;-o-transition:.2s ease-in-out;transition:.2s ease-in-out;display:inline-block;max-width:100%;height:auto} .img-circle{border-radius:50%} -hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee} +hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee} .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} .sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} [role=button]{cursor:pointer} @@ -351,13 +345,13 @@ hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee} .h6,h6{font-size:12px} p{margin:0 0 10px} .lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4} -dt,kbd kbd,label{font-weight:700} -address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143} -@media (min-width:768px){.lead{font-size:21px} +@media (min-width:768px){ +.lead{font-size:21px} +.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.dl-horizontal dd{margin-left:180px} } .small,small{font-size:85%} .mark,mark{padding:.2em;background-color:#fcf8e3} -.list-inline,.list-unstyled{padding-left:0;list-style:none} .text-left{text-align:left} .text-right{text-align:right} .text-center{text-align:center} @@ -387,45 +381,49 @@ a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee} a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5} .bg-danger{background-color:#f2dede} a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9} -pre code,table{background-color:transparent} .page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee} -dl,ol,ul{margin-top:0} -blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child,ol ol,ol ul,ul ol,ul ul{margin-bottom:0} -address,dl{margin-bottom:20px} -ol,ul{margin-bottom:10px} -.list-inline{margin-left:-5px} +ol,ul{margin-top:0;margin-bottom:10px} +ol ol,ol ul,ul ol,ul ul{margin-bottom:0} +.list-unstyled{padding-left:0;list-style:none} +.list-inline{padding-left:0;list-style:none;margin-left:-5px} .list-inline>li{display:inline-block;padding-right:5px;padding-left:5px} +dl{margin-top:0;margin-bottom:20px} +dd,dt{line-height:1.42857143} +dt{font-weight:700} dd{margin-left:0} -@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap} -.dl-horizontal dd{margin-left:180px} -.container{width:750px} -} -abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777} +abbr[data-original-title],abbr[title]{cursor:help} .initialism{font-size:90%;text-transform:uppercase} blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee} -blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#777} -legend,pre{display:block;color:#333} -blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'} +blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0} +blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777} +blockquote .small:before,blockquote footer:before,blockquote small:before{content:"\2014 \00A0"} .blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0} -code,kbd{padding:2px 4px;font-size:90%} -caption,th{text-align:left} -.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''} -.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'} +.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:""} +.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:"\00A0 \2014"} +address{margin-bottom:20px;font-style:normal;line-height:1.42857143} code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace} -code{color:#c7254e;background-color:#f9f2f4;border-radius:4px} -kbd{color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)} -kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none} -pre{padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px} -.container,.container-fluid{margin-right:auto;margin-left:auto} -pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0} -.container,.container-fluid{padding-right:15px;padding-left:15px} -.pre-scrollable{overflow-y:scroll} -@media (min-width:992px){.container{width:970px} +code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px} +kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)} +kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none} +pre{overflow:auto;display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px} +pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0} +.pre-scrollable{max-height:340px;overflow-y:scroll} +.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto} +@media (min-width:768px){ +.container{width:750px} +} +@media (min-width:992px){ +.container{width:970px} } -@media (min-width:1200px){.container{width:1170px} +@media (min-width:1200px){ +.container{width:1170px} } +.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto} .row{margin-right:-15px;margin-left:-15px} +.row-no-gutters{margin-right:0;margin-left:0} +.row-no-gutters [class*=col-]{padding-right:0;padding-left:0} .col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px} +.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left} .col-xs-12{width:100%} .col-xs-11{width:91.66666667%} .col-xs-10{width:83.33333333%} @@ -477,7 +475,8 @@ pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-r .col-xs-offset-2{margin-left:16.66666667%} .col-xs-offset-1{margin-left:8.33333333%} .col-xs-offset-0{margin-left:0} -@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left} +@media (min-width:768px){ +.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left} .col-sm-12{width:100%} .col-sm-11{width:91.66666667%} .col-sm-10{width:83.33333333%} @@ -530,7 +529,8 @@ pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-r .col-sm-offset-1{margin-left:8.33333333%} .col-sm-offset-0{margin-left:0} } -@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left} +@media (min-width:992px){ +.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left} .col-md-12{width:100%} .col-md-11{width:91.66666667%} .col-md-10{width:83.33333333%} @@ -583,7 +583,8 @@ pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-r .col-md-offset-1{margin-left:8.33333333%} .col-md-offset-0{margin-left:0} } -@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left} +@media (min-width:1200px){ +.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left} .col-lg-12{width:100%} .col-lg-11{width:91.66666667%} .col-lg-10{width:83.33333333%} @@ -636,7 +637,11 @@ pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-r .col-lg-offset-1{margin-left:8.33333333%} .col-lg-offset-0{margin-left:0} } -caption{padding-top:8px;padding-bottom:8px;color:#777} +table{border-collapse:collapse;border-spacing:0;background-color:transparent} +table col[class*=col-]{position:static;display:table-column;float:none} +table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none} +caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left} +th{text-align:left} .table{width:100%;max-width:100%;margin-bottom:20px} .table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd} .table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd} @@ -648,8 +653,6 @@ caption{padding-top:8px;padding-bottom:8px;color:#777} .table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px} .table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9} .table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5} -table col[class*=col-]{position:static;display:table-column;float:none} -table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none} .table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8} .table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8} .table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6} @@ -660,7 +663,8 @@ table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;f .table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede} .table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc} .table-responsive{min-height:.01%;overflow-x:auto} -@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd} +@media screen and (max-width:767px){ +.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd} .table-responsive>.table{margin-bottom:0} .table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap} .table-responsive>.table-bordered{border:0} @@ -668,137 +672,144 @@ table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;f .table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0} .table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0} } -fieldset,legend{padding:0;border:0} -fieldset{min-width:0;margin:0} -legend{width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;border-bottom:1px solid #e5e5e5} -label{display:inline-block;max-width:100%;margin-bottom:5px} -input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none} -input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal} -.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block} +fieldset{min-width:0;padding:0;margin:0;border:0} +legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5} +label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700} +input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none} +input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal} +fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed} input[type=file]{display:block} input[type=range]{display:block;width:100%} select[multiple],select[size]{height:auto} -input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} -output{padding-top:7px} -.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s} +input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555} +.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;-o-transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-box-shadow .15s ease-in-out} .form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)} .form-control::-moz-placeholder{color:#999;opacity:1} .form-control:-ms-input-placeholder{color:#999} .form-control::-webkit-input-placeholder{color:#999} -.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d} .form-control::-ms-expand{background-color:transparent;border:0} .form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1} .form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed} textarea.form-control{height:auto} -@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px} -.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px} -.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px} +@media screen and (-webkit-min-device-pixel-ratio:0){ +input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:34px} +.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px} +.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px} } .form-group{margin-bottom:15px} .checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px} +.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed} .checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer} -.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px} +.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px} .checkbox+.checkbox,.radio+.radio{margin-top:-5px} .checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer} +.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed} .checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px} -.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed} .form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0} .form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0} -.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px} -.input-sm{height:30px;line-height:1.5} +.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px} select.input-sm{height:30px;line-height:30px} select[multiple].input-sm,textarea.input-sm{height:auto} -.form-group-sm .form-control{height:30px;line-height:1.5} -.form-group-lg .form-control,.input-lg{border-radius:6px;padding:10px 16px;font-size:18px} +.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px} .form-group-sm select.form-control{height:30px;line-height:30px} .form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto} .form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5} -.input-lg{height:46px;line-height:1.3333333} +.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px} select.input-lg{height:46px;line-height:46px} select[multiple].input-lg,textarea.input-lg{height:auto} -.form-group-lg .form-control{height:46px;line-height:1.3333333} +.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px} .form-group-lg select.form-control{height:46px;line-height:46px} .form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto} .form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333} .has-feedback{position:relative} .has-feedback .form-control{padding-right:42.5px} .form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none} -.collapsing,.dropdown,.dropup{position:relative} .form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px} .form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px} +.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d} .has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} .has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168} .has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d} -.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b} +.has-success .form-control-feedback{color:#3c763d} +.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b} .has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} .has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b} .has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b} -.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442} +.has-warning .form-control-feedback{color:#8a6d3b} +.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442} .has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)} .has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483} .has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442} +.has-error .form-control-feedback{color:#a94442} .has-feedback label~.form-control-feedback{top:25px} .has-feedback label.sr-only~.form-control-feedback{top:0} .help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373} -@media (min-width:768px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block} -.form-inline .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle} +.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0} +.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px} +.form-horizontal .form-group{margin-right:-15px;margin-left:-15px} +.form-horizontal .has-feedback .form-control-feedback{right:15px} +@media (min-width:768px){ +.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle} .form-inline .form-control{display:inline-block;width:auto;vertical-align:middle} +.form-inline .form-control-static{display:inline-block} .form-inline .input-group{display:inline-table;vertical-align:middle} .form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto} .form-inline .input-group>.form-control{width:100%} +.form-inline .control-label{margin-bottom:0;vertical-align:middle} .form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle} .form-inline .checkbox label,.form-inline .radio label{padding-left:0} .form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0} .form-inline .has-feedback .form-control-feedback{top:0} .form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right} -} -.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0} -.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px} -.form-horizontal .form-group{margin-right:-15px;margin-left:-15px} -.form-horizontal .has-feedback .form-control-feedback{right:15px} -@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px} +.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px} .form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px} } -.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;border-radius:4px} +.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} .btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none} -.btn.active,.btn:active{outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} -.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65} +.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} +.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;-webkit-box-shadow:none;box-shadow:none} a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none} .btn-default{color:#333;background-color:#fff;border-color:#ccc} .btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c} -.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad} +.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad} +.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;background-image:none;border-color:#adadad} .btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c} .btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc} .btn-default .badge{color:#fff;background-color:#333} .btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4} .btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40} -.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74} +.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74} +.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;background-image:none;border-color:#204d74} .btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40} .btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4} .btn-primary .badge{color:#337ab7;background-color:#fff} .btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c} .btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625} -.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439} +.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439} +.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;background-image:none;border-color:#398439} .btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625} -.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none} .btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c} .btn-success .badge{color:#5cb85c;background-color:#fff} .btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da} .btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85} -.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc} +.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc} +.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;background-image:none;border-color:#269abc} .btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85} .btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da} .btn-info .badge{color:#5bc0de;background-color:#fff} .btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236} .btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d} -.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512} +.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512} +.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;background-image:none;border-color:#d58512} .btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d} .btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236} .btn-warning .badge{color:#f0ad4e;background-color:#fff} .btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a} .btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19} -.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925} +.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925} +.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;background-image:none;border-color:#ac2925} .btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19} .btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a} .btn-danger .badge{color:#d9534f;background-color:#fff} @@ -819,50 +830,54 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .collapse.in{display:block} tr.collapse.in{display:table-row} tbody.collapse.in{display:table-row-group} -.collapsing{height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility} -.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent} +.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease} +.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent} +.dropdown,.dropup{position:relative} .dropdown-toggle:focus{outline:0} -.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)} -.dropdown-menu-right,.dropdown-menu.pull-right{right:0;left:auto} -.dropdown-header,.dropdown-menu>li>a{display:block;padding:3px 20px;line-height:1.42857143;white-space:nowrap} -.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle,.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0} -.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child,.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0} -.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)} +.dropdown-menu.pull-right{right:0;left:auto} .dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5} -.dropdown-menu>li>a{clear:both;font-weight:400;color:#333} +.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap} .dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5} .dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0} .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777} -.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)} +.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none} .open>.dropdown-menu{display:block} .open>a{outline:0} +.dropdown-menu-right{right:0;left:auto} .dropdown-menu-left{right:auto;left:0} -.dropdown-header{font-size:12px;color:#777} +.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap} .dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990} -.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto} .pull-right>.dropdown-menu{right:0;left:auto} -.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed} .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px} -@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto} -.navbar-right .dropdown-menu-left{right:auto;left:0} -} .btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle} .btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left} .btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2} .btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px} .btn-toolbar{margin-left:-5px} +.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left} .btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px} -.btn .caret,.btn-group>.btn:first-child{margin-left:0} +.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0} +.btn-group>.btn:first-child{margin-left:0} +.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0} +.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0} +.btn-group>.btn-group{float:left} +.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0} +.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0} +.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0} .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0} .btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px} .btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px} .btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)} .btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none} +.btn .caret{margin-left:0} .btn-lg .caret{border-width:5px 5px 0} .dropup .btn-lg .caret{border-width:0 5px 5px} .btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%} .btn-group-vertical>.btn-group>.btn{float:none} .btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0} +.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0} .btn-group-vertical>.btn:first-child:not(:last-child){border-radius:4px 4px 0 0} .btn-group-vertical>.btn:last-child:not(:first-child){border-radius:0 0 4px 4px} .btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0} @@ -884,7 +899,6 @@ select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.i select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px} select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto} .input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell} -.nav>li,.nav>li>a{display:block;position:relative} .input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0} .input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle} .input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px} @@ -902,7 +916,8 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px} .input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px} .nav{padding-left:0;margin-bottom:0;list-style:none} -.nav>li>a{padding:10px 15px} +.nav>li{position:relative;display:block} +.nav>li>a{position:relative;display:block;padding:10px 15px} .nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee} .nav>li.disabled>a{color:#777} .nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent} @@ -917,24 +932,31 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .nav-tabs.nav-justified{width:100%;border-bottom:0} .nav-tabs.nav-justified>li{float:none} .nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center;margin-right:0;border-radius:4px} +.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd} -@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%} -.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} -.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff} -} .nav-pills>li{float:left} -.nav-justified>li,.nav-stacked>li{float:none} .nav-pills>li>a{border-radius:4px} .nav-pills>li+li{margin-left:2px} .nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7} +.nav-stacked>li{float:none} .nav-stacked>li+li{margin-top:2px;margin-left:0} .nav-justified{width:100%} +.nav-justified>li{float:none} .nav-justified>li>a{margin-bottom:5px;text-align:center} +.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto} +@media (min-width:768px){ +.navbar-right .dropdown-menu{right:0;left:auto} +.navbar-right .dropdown-menu-left{right:auto;left:0} +.nav-tabs.nav-justified>li{display:table-cell;width:1%} +.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} +.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff} +.nav-justified>li{display:table-cell;width:1%} +.nav-justified>li>a{margin-bottom:0} +} .nav-tabs-justified{border-bottom:0} .nav-tabs-justified>li>a{margin-right:0;border-radius:4px} .nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd} -@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%} -.nav-justified>li>a{margin-bottom:0} +@media (min-width:768px){ .nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0} .nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff} } @@ -942,64 +964,75 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .tab-content>.active{display:block} .nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0} .navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent} -.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)} +.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch} .navbar-collapse.in{overflow-y:auto} -@media (min-width:768px){.navbar{border-radius:4px} +.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030} +.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px} +@media (max-device-width:480px) and (orientation:landscape){ +.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px} +} +@media (min-width:768px){ +.navbar{border-radius:4px} .navbar-header{float:left} .navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none} .navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important} .navbar-collapse.in{overflow-y:visible} .navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0} +.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0} } -.embed-responsive,.modal,.modal-open,.progress{overflow:hidden} -@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px} -} -.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px} -.navbar-static-top{z-index:1000;border-width:0 0 1px} -.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030} .navbar-fixed-top{top:0;border-width:0 0 1px} .navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0} +.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px} +.navbar-static-top{z-index:1000;border-width:0 0 1px} .navbar-brand{float:left;height:50px;padding:15px;font-size:18px;line-height:20px} .navbar-brand:focus,.navbar-brand:hover{text-decoration:none} .navbar-brand>img{display:block} -@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0} -.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0} +@media (min-width:768px){ +.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0} +.navbar-static-top{border-radius:0} .navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px} +.navbar-toggle{display:none} } -.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px} +.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-right:15px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px} .navbar-toggle:focus{outline:0} .navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px} .navbar-toggle .icon-bar+.icon-bar{margin-top:4px} .navbar-nav{margin:7.5px -15px} .navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px} -@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none} +@media (max-width:767px){ +.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none} .navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px} .navbar-nav .open .dropdown-menu>li>a{line-height:20px} .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none} } -.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} -@media (min-width:768px){.navbar-toggle{display:none} +@media (min-width:768px){ .navbar-nav{float:left;margin:0} .navbar-nav>li{float:left} .navbar-nav>li>a{padding-top:15px;padding-bottom:15px} -} -.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px} -@media (min-width:768px){.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block} -.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle} +.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle} .navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle} +.navbar-form .form-control-static{display:inline-block} .navbar-form .input-group{display:inline-table;vertical-align:middle} .navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto} .navbar-form .input-group>.form-control{width:100%} +.navbar-form .control-label{margin-bottom:0;vertical-align:middle} .navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle} .navbar-form .checkbox label,.navbar-form .radio label{padding-left:0} .navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0} .navbar-form .has-feedback .form-control-feedback{top:0} -.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none} } -.breadcrumb>li,.pagination{display:inline-block} -.btn .badge,.btn .label{top:-1px;position:relative} -@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px} +.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px} +@media (max-width:767px){ +.navbar-form .form-group{margin-bottom:5px} .navbar-form .form-group:last-child{margin-bottom:0} +.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777} +.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent} +.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7} +.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent} +} +@media (min-width:768px){ +.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none} +.navbar-text{float:left;margin-right:15px;margin-left:15px} } .navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0} .navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:4px 4px 0 0} @@ -1007,7 +1040,7 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px} .navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px} .navbar-text{margin-top:15px;margin-bottom:15px} -@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px} +@media (min-width:768px){ .navbar-left{float:left!important} .navbar-right{float:right!important;margin-right:-15px} .navbar-right~.navbar-right{margin-right:0} @@ -1019,16 +1052,11 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent} .navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7} .navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent} +.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7} .navbar-default .navbar-toggle{border-color:#ddd} .navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd} .navbar-default .navbar-toggle .icon-bar{background-color:#888} .navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7} -.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7} -@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777} -.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent} -.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7} -.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent} -} .navbar-default .navbar-link{color:#777} .navbar-default .navbar-link:hover{color:#333} .navbar-default .btn-link{color:#777} @@ -1041,50 +1069,53 @@ select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.i .navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent} .navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808} .navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent} -.navbar-inverse .navbar-toggle{border-color:#333} -.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333} -.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff} -.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010} .navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808} -@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808} +@media (max-width:767px){ +.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808} .navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808} .navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d} .navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent} .navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808} .navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent} } +.navbar-inverse .navbar-toggle{border-color:#333} +.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333} +.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff} +.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010} .navbar-inverse .navbar-link{color:#9d9d9d} .navbar-inverse .navbar-link:hover{color:#fff} .navbar-inverse .btn-link{color:#9d9d9d} .navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff} .navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444} .breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px} +.breadcrumb>li{display:inline-block} .breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"} .breadcrumb>.active{color:#777} -.pagination{padding-left:0;margin:20px 0;border-radius:4px} -.pager li,.pagination>li{display:inline} +.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px} +.pagination>li{display:inline} .pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd} +.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd} .pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px} .pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px} -.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd} .pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7} .pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd} .pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333} .pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px} .pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px} .pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5} -.badge,.label{font-weight:700;line-height:1;white-space:nowrap;text-align:center} .pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px} .pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px} .pager{padding-left:0;margin:20px 0;text-align:center;list-style:none} +.pager li{display:inline} .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px} .pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee} .pager .next>a,.pager .next>span{float:right} .pager .previous>a,.pager .previous>span{float:left} .pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff} -a.badge:focus,a.badge:hover,a.label:focus,a.label:hover{color:#fff;cursor:pointer;text-decoration:none} -.label{display:inline;padding:.2em .6em .3em;font-size:75%;color:#fff;border-radius:.25em} +.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em} +a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer} .label:empty{display:none} +.btn .label{position:relative;top:-1px} .label-default{background-color:#777} .label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e} .label-primary{background-color:#337ab7} @@ -1097,37 +1128,37 @@ a.badge:focus,a.badge:hover,a.label:focus,a.label:hover{color:#fff;cursor:pointe .label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f} .label-danger{background-color:#d9534f} .label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c} -.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;color:#fff;vertical-align:middle;background-color:#777;border-radius:10px} +.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px} .badge:empty{display:none} -.media-object,.thumbnail{display:block} +.btn .badge{position:relative;top:-1px} .btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px} +a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer} .list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff} -.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit} .list-group-item>.badge{float:right} .list-group-item>.badge+.badge{margin-right:5px} .nav-pills>li>a>.badge{margin-left:3px} -.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;background-color:#eee} +.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee} +.jumbotron .h1,.jumbotron h1{color:inherit} .jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200} -.alert,.thumbnail{margin-bottom:20px} -.alert .alert-link,.close{font-weight:700} .jumbotron>hr{border-top-color:#d5d5d5} .container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px} .jumbotron .container{max-width:100%} -@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px} +@media screen and (min-width:768px){ +.jumbotron{padding-top:48px;padding-bottom:48px} .container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px} .jumbotron .h1,.jumbotron h1{font-size:63px} } -.thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out} +.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out} .thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto} a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7} .thumbnail .caption{padding:9px;color:#333} -.alert{padding:15px;border:1px solid transparent;border-radius:4px} +.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px} .alert h4{margin-top:0;color:inherit} +.alert .alert-link{font-weight:700} .alert>p,.alert>ul{margin-bottom:0} .alert>p+p{margin-top:5px} .alert-dismissable,.alert-dismissible{padding-right:35px} .alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit} -.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0} .alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6} .alert-success hr{border-top-color:#c9e2b3} .alert-success .alert-link{color:#2b542c} @@ -1140,32 +1171,35 @@ a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7} .alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1} .alert-danger hr{border-top-color:#e4b9c0} .alert-danger .alert-link{color:#843534} -@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} +@-webkit-keyframes progress-bar-stripes{ +from{background-position:40px 0} to{background-position:0 0} } -@-o-keyframes progress-bar-stripes{from{background-position:40px 0} +@-o-keyframes progress-bar-stripes{ +from{background-position:40px 0} to{background-position:0 0} } -@keyframes progress-bar-stripes{from{background-position:40px 0} +@keyframes progress-bar-stripes{ +from{background-position:40px 0} to{background-position:0 0} } -.progress{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)} -.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease} -.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px} -.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite} +.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)} +.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s;-o-transition:width .6s;transition:width .6s} +.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px} +.progress-bar.active,.progress.active .progress-bar{-webkit-animation:2s linear infinite progress-bar-stripes;-o-animation:2s linear infinite progress-bar-stripes;animation:2s linear infinite progress-bar-stripes} .progress-bar-success{background-color:#5cb85c} -.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} -.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} .progress-bar-info{background-color:#5bc0de} -.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} .progress-bar-warning{background-color:#f0ad4e} -.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} +.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} .progress-bar-danger{background-color:#d9534f} .progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)} .media{margin-top:15px} .media:first-child{margin-top:0} .media,.media-body{overflow:hidden;zoom:1} .media-body{width:10000px} +.media-object{display:block} .media-object.img-thumbnail{max-width:none} .media-right,.media>.pull-right{padding-left:10px} .media-left,.media>.pull-left{padding-right:10px} @@ -1178,16 +1212,16 @@ to{background-position:0 0} .list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd} .list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px} .list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px} -a.list-group-item,button.list-group-item{color:#555} -a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333} -a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5} -button.list-group-item{width:100%;text-align:left} .list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee} .list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit} .list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777} .list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7} .list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit} .list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef} +a.list-group-item,button.list-group-item{color:#555} +a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333} +a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5} +button.list-group-item{width:100%;text-align:left} .list-group-item-success{color:#3c763d;background-color:#dff0d8} a.list-group-item-success,button.list-group-item-success{color:#3c763d} a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit} @@ -1208,21 +1242,22 @@ a.list-group-item-danger,button.list-group-item-danger{color:#a94442} a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit} a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc} a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442} -.panel-heading>.dropdown .dropdown-toggle,.panel-title,.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit} .list-group-item-heading{margin-top:0;margin-bottom:5px} .list-group-item-text{margin-bottom:0;line-height:1.3} .panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)} -.panel-title,.panel>.list-group,.panel>.panel-collapse>.list-group,.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0} .panel-body{padding:15px} .panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px} -.panel-title{margin-top:0;font-size:16px} +.panel-heading>.dropdown .dropdown-toggle{color:inherit} +.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit} +.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit} .panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px} +.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0} .panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0} -.panel-group .panel-heading,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0} .panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px} .panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px} .panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0} .list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0} +.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0} .panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px} .panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px} .panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px} @@ -1235,10 +1270,12 @@ a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-gro .panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0} .panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0} .panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0} +.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0} .panel>.table-responsive{margin-bottom:0;border:0} .panel-group{margin-bottom:20px} .panel-group .panel{margin-bottom:0;border-radius:4px} .panel-group .panel+.panel{margin-top:5px} +.panel-group .panel-heading{border-bottom:0} .panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd} .panel-group .panel-footer{border-top:0} .panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd} @@ -1272,27 +1309,27 @@ a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-gro .panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1} .panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442} .panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1} -.embed-responsive{position:relative;display:block;height:0;padding:0} +.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden} .embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0} .embed-responsive-16by9{padding-bottom:56.25%} .embed-responsive-4by3{padding-bottom:75%} .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)} -.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)} +.well blockquote{border-color:rgba(0,0,0,.15)} .well-lg{padding:24px;border-radius:6px} .well-sm{padding:9px;border-radius:3px} -.close{float:right;font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2} -.popover,.tooltip{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;line-break:auto;text-decoration:none} -.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5} -button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0} -.modal{position:fixed;z-index:1050;display:none;-webkit-overflow-scrolling:touch;outline:0} -.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)} +.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2} +.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5} +button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none} +.modal-open{overflow:hidden} +.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0} +.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out,-o-transform .3s ease-out} .modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)} .modal-open .modal{overflow-x:hidden;overflow-y:auto} .modal-dialog{position:relative;width:auto;margin:10px} -.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)} -.modal-backdrop{position:fixed;z-index:1040;background-color:#000} -.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0} -.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5} +.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000} +.modal-backdrop.fade{opacity:0} +.modal-backdrop.in{opacity:.5} .modal-header{padding:15px;border-bottom:1px solid #e5e5e5} .modal-header .close{margin-top:-2px} .modal-title{margin:0;line-height:1.42857143} @@ -1302,58 +1339,57 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .modal-footer .btn-group .btn+.btn{margin-left:-1px} .modal-footer .btn-block+.btn-block{margin-left:0} .modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll} -@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto} +@media (min-width:768px){ +.modal-dialog{width:600px;margin:30px auto} .modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)} .modal-sm{width:300px} } -@media (min-width:992px){.modal-lg{width:900px} +@media (min-width:992px){ +.modal-lg{width:900px} } -.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;text-align:left;text-align:start;filter:alpha(opacity=0);opacity:0} -.tooltip.in{filter:alpha(opacity=90);opacity:.9} +.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:12px;opacity:0} +.tooltip.in{opacity:.9} .tooltip.top{padding:5px 0;margin-top:-3px} .tooltip.right{padding:0 5px;margin-left:3px} .tooltip.bottom{padding:5px 0;margin-top:3px} .tooltip.left{padding:0 5px;margin-left:-3px} -.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px} -.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid} -.tooltip.top .tooltip-arrow,.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;border-width:5px 5px 0;border-top-color:#000} -.tooltip.top .tooltip-arrow{left:50%;margin-left:-5px} -.tooltip.top-left .tooltip-arrow{right:5px;margin-bottom:-5px} -.tooltip.top-right .tooltip-arrow{left:5px;margin-bottom:-5px} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000} +.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000} +.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000} .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000} .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000} -.tooltip.bottom .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow{border-width:0 5px 5px;border-bottom-color:#000;top:0} -.tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px} -.tooltip.bottom-left .tooltip-arrow{right:5px;margin-top:-5px} -.tooltip.bottom-right .tooltip-arrow{left:5px;margin-top:-5px} -.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;text-align:left;text-align:start;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)} -.carousel-caption,.carousel-control{color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000} +.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000} +.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000} +.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px} +.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid} +.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:14px;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)} .popover.top{margin-top:-10px} .popover.right{margin-left:10px} .popover.bottom{margin-top:10px} .popover.left{margin-left:-10px} -.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0} -.popover-content{padding:9px 14px} -.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid} -.carousel,.carousel-inner{position:relative} .popover>.arrow{border-width:11px} +.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid} .popover>.arrow:after{content:"";border-width:10px} -.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} +.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} .popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0} -.popover.left>.arrow:after,.popover.right>.arrow:after{bottom:-10px;content:" "} -.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0} -.popover.right>.arrow:after{left:1px;border-right-color:#fff;border-left-width:0} -.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)} +.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25);border-left-width:0} +.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0} +.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:rgba(0,0,0,.25)} .popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff} -.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)} -.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff} -.carousel-inner{width:100%;overflow:hidden} -.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left} +.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:rgba(0,0,0,.25)} +.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff} +.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0} +.popover-content{padding:9px 14px} +.carousel{position:relative} +.carousel-inner{position:relative;width:100%;overflow:hidden} +.carousel-inner>.item{position:relative;display:none;-webkit-transition:left .6s ease-in-out;-o-transition:left .6s ease-in-out;transition:left .6s ease-in-out} .carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1} -@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px} -.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)} -.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)} -.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)} +@media all and (transform-3d),(-webkit-transform-3d){ +.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out,-o-transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px} +.carousel-inner>.item.active.right,.carousel-inner>.item.next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);left:0} +.carousel-inner>.item.active.left,.carousel-inner>.item.prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);left:0} +.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);left:0} } .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block} .carousel-inner>.active{left:0} @@ -1363,22 +1399,23 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0} .carousel-inner>.active.left{left:-100%} .carousel-inner>.active.right{left:100%} -.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5} -.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x} -.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x} -.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9} +.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);opacity:.5} +.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x} +.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x} +.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9} .carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px} .carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px} .carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px} .carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1} -.carousel-control .icon-prev:before{content:'\2039'} -.carousel-control .icon-next:before{content:'\203a'} +.carousel-control .icon-prev:before{content:"\2039"} +.carousel-control .icon-next:before{content:"\203a"} .carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none} -.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px} +.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px} .carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff} -.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px} -.carousel-caption .btn,.text-hide{text-shadow:none} -@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px} +.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)} +.carousel-caption .btn{text-shadow:none} +@media screen and (min-width:768px){ +.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px} .carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px} .carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px} .carousel-caption{right:20%;left:20%;padding-bottom:30px} @@ -1391,12 +1428,14 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .pull-left{float:left!important} .hide{display:none!important} .show{display:block!important} -.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important} .invisible{visibility:hidden} -.text-hide{font:0/0 a;color:transparent;background-color:transparent;border:0} +.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.hidden{display:none!important} .affix{position:fixed} @-ms-viewport{width:device-width} -@media (max-width:767px){.visible-xs{display:block!important} +.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important} +@media (max-width:767px){ +.visible-xs{display:block!important} table.visible-xs{display:table!important} tr.visible-xs{display:table-row!important} td.visible-xs,th.visible-xs{display:table-cell!important} @@ -1404,7 +1443,8 @@ td.visible-xs,th.visible-xs{display:table-cell!important} .visible-xs-inline{display:inline!important} .visible-xs-inline-block{display:inline-block!important} } -@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important} +@media (min-width:768px) and (max-width:991px){ +.visible-sm{display:block!important} table.visible-sm{display:table!important} tr.visible-sm{display:table-row!important} td.visible-sm,th.visible-sm{display:table-cell!important} @@ -1412,7 +1452,8 @@ td.visible-sm,th.visible-sm{display:table-cell!important} .visible-sm-inline{display:inline!important} .visible-sm-inline-block{display:inline-block!important} } -@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important} +@media (min-width:992px) and (max-width:1199px){ +.visible-md{display:block!important} table.visible-md{display:table!important} tr.visible-md{display:table-row!important} td.visible-md,th.visible-md{display:table-cell!important} @@ -1420,7 +1461,8 @@ td.visible-md,th.visible-md{display:table-cell!important} .visible-md-inline{display:inline!important} .visible-md-inline-block{display:inline-block!important} } -@media (min-width:1200px){.visible-lg{display:block!important} +@media (min-width:1200px){ +.visible-lg{display:block!important} table.visible-lg{display:table!important} tr.visible-lg{display:table-row!important} td.visible-lg,th.visible-lg{display:table-cell!important} @@ -1429,26 +1471,33 @@ td.visible-lg,th.visible-lg{display:table-cell!important} .visible-lg-inline-block{display:inline-block!important} .hidden-lg{display:none!important} } -@media (max-width:767px){.hidden-xs{display:none!important} +@media (max-width:767px){ +.hidden-xs{display:none!important} } -@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important} +@media (min-width:768px) and (max-width:991px){ +.hidden-sm{display:none!important} } -@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important} +@media (min-width:992px) and (max-width:1199px){ +.hidden-md{display:none!important} } .visible-print{display:none!important} -@media print{.visible-print{display:block!important} +@media print{ +.visible-print{display:block!important} table.visible-print{display:table!important} tr.visible-print{display:table-row!important} td.visible-print,th.visible-print{display:table-cell!important} } .visible-print-block{display:none!important} -@media print{.visible-print-block{display:block!important} +@media print{ +.visible-print-block{display:block!important} } .visible-print-inline{display:none!important} -@media print{.visible-print-inline{display:inline!important} +@media print{ +.visible-print-inline{display:inline!important} } .visible-print-inline-block{display:none!important} -@media print{.visible-print-inline-block{display:inline-block!important} +@media print{ +.visible-print-inline-block{display:inline-block!important} .hidden-print{display:none!important} } .hljs{display:block;background:#fff;padding:.5em;color:#333;overflow-x:auto} diff --git a/docs/styles/docfx.vendor.js b/docs/styles/docfx.vendor.js index 81dab091..5d30fc0c 100644 --- a/docs/styles/docfx.vendor.js +++ b/docs/styles/docfx.vendor.js @@ -1,55 +1 @@ -/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){ -return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*\s*$/g,ia={option:[1,""],thead:[1,"","
                                                                                                                                "],col:[2,"","
                                                                                                                                "],tr:[2,"","
                                                                                                                                "],td:[3,"","
                                                                                                                                "],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("