public void AnonymousTypeTupletizer_TransparentIdentifiers() { Expression <Func <IEnumerable <int>, IEnumerable <string>, IEnumerable <bool> > > f = (xs, ys) => from x in xs from y in ys let l = y.Length let k = x * l where l > 0 where k != 1 let b = x + l < 42 select !b; //Expression<Func<IEnumerable<int>, IEnumerable<string>, IEnumerable<bool>>> g = (xs, ys) => xs // .SelectMany(x => ys, (x, y) => new { x = x, y = y }) // .Select(t => new { t, l = t.y.Length }) // .Select(t => new { t, k = t.t.x * t.l }) // .Where(t => t.t.l > 0) // .Where(t => t.k != 1) // .Select(t => new { t, b = t.t.t.x + t.t.l < 42 }) // .Select(t => !t.b); Expression <Func <IEnumerable <int>, IEnumerable <string>, IEnumerable <bool> > > g = (xs, ys) => xs .SelectMany(x => ys, (x, y) => new Tuple <int, string>(x, y)) .Select(t => new Tuple <Tuple <int, string>, int>(t, t.Item2.Length)) .Select(t => new Tuple <Tuple <Tuple <int, string>, int>, int>(t, t.Item1.Item1 * t.Item2)) .Where(t => t.Item1.Item2 > 0) .Where(t => t.Item2 != 1) .Select(t => new Tuple <Tuple <Tuple <Tuple <int, string>, int>, int>, bool>(t, t.Item1.Item1.Item1 + t.Item1.Item2 < 42)) .Select(t => !t.Item2); var te = AnonymousTypeTupletizer.Tupletize(f, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(g, te)); }
public void ConstantHoister_ManOrBoy() { #pragma warning disable IDE0079 // The following supression is flagged as unnecessary on .NET Framework (but is required for other targets) #pragma warning disable CA1845 // Use span-based 'string.Concat' and 'AsSpan' instead of 'Substring' var e = (Expression <Func <IEnumerable <int>, IEnumerable <string> > >)(xs => from x in xs let y = x + 1 where y > 0 let s = x.ToString() where !s.EndsWith("Foo") select s.Substring(0, 1) + "Foo"); #pragma warning restore CA1847 #pragma warning restore IDE0079 var c = ConstantHoister.Hoist(e, useDefaultForNull: false); Assert.AreEqual(3, c.Environment.Count); Assert.IsTrue(c.Environment.Values.Contains(0)); Assert.IsTrue(c.Environment.Values.Contains(1)); Assert.IsTrue(c.Environment.Values.Contains("Foo")); var i = (Expression)c.ToInvocation(); Assert.AreEqual("((Func<int, int, string, Func<IEnumerable<int>, IEnumerable<string>>>)((int @p0, int @p1, string @p2) => (IEnumerable<int> xs) => xs.Select((int x) => new { x, y = x + @p0 }).Where(t => t.y > @p1).Select(t => new { t, s = t.x.ToString() }).Where(t => !t.s.EndsWith(@p2)).Select(t => t.s.Substring(@p1, @p0) + @p2)))(1, 0, \"Foo\")", i.ToCSharpString()); Assert.AreEqual("int @p0 = 1;\r\nint @p1 = 0;\r\nstring @p2 = \"Foo\";\r\nreturn (IEnumerable<int> xs) => xs.Select((int x) => new { x, y = x + @p0 }).Where(t => t.y > @p1).Select(t => new { t, s = t.x.ToString() }).Where(t => !t.s.EndsWith(@p2)).Select(t => t.s.Substring(@p1, @p0) + @p2);\r\n", c.ToCSharpString()); var t = c.ToString(); var u = Regex.Replace(t, @"\<\>f__AnonymousType[\da-fA-F]*", "anon"); var v = Regex.Replace(u, @"\<\>h__TransparentIdentifier[\da-fA-F]*", "tran"); Assert.AreEqual("(xs => xs.Select(x => new anon`2(x = x, y = (x + @p0))).Where(tran => (tran.y > @p1)).Select(tran => new anon`2(tran = tran, s = tran.x.ToString())).Where(tran => Not(tran.s.EndsWith(@p2))).Select(tran => (tran.s.Substring(@p1, @p0) + @p2)))[|@p0 : System.Int32 = 1, @p1 : System.Int32 = 0, @p2 : System.String = \"Foo\"|]", v); i = AnonymousTypeTupletizer.Tupletize(i, Expression.Constant(value: null)); i = CompilerGeneratedNameEliminator.Prettify(i); var f = i.Evaluate <Func <IEnumerable <int>, IEnumerable <string> > >(); var g = f(new[] { 123, 234, 987, 876 }); Assert.IsTrue(new[] { "1Foo", "2Foo", "9Foo", "8Foo" }.SequenceEqual(g)); Assert.AreEqual(@"Invoke((@p0, @p1, @p2) => xs => xs.Select(x => new Tuple`2(x, (x + @p0))).Where(t => (t.Item2 > @p1)).Select(t => new Tuple`2(t, t.Item1.ToString())).Where(t => Not(t.Item2.EndsWith(@p2))).Select(t => (t.Item2.Substring(@p1, @p0) + @p2)), 1, 0, ""Foo"")", i.ToString()); }
public void AnonymousTypeTupletizer_RecursiveType() { var rtc = new RuntimeCompiler(); var atb1 = rtc.GetNewAnonymousTypeBuilder(); var atb2 = rtc.GetNewAnonymousTypeBuilder(); rtc.DefineAnonymousType(atb1, new[] { new KeyValuePair <string, Type>("Qux", typeof(int)), new KeyValuePair <string, Type>("Bar", atb2), }, Array.Empty <string>()); rtc.DefineAnonymousType(atb2, new[] { new KeyValuePair <string, Type>("Baz", typeof(int)), new KeyValuePair <string, Type>("Foo", atb1), }, Array.Empty <string>()); var foo = atb1.CreateType(); var bar = atb2.CreateType(); var e = Expression.New(foo.GetConstructors().Single(), Expression.Constant(1), Expression.Constant(value: null, bar)); Assert.ThrowsException <NotSupportedException>(() => AnonymousTypeTupletizer.Tupletize(e, Expression.Constant(value: null))); }
public void AnonymousTypeTupletizer_ArgumentChecking() { AssertEx.ThrowsException <ArgumentNullException>(() => AnonymousTypeTupletizer.Tupletize(expression: null, Expression.Constant(1)), ex => Assert.AreEqual("expression", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => AnonymousTypeTupletizer.Tupletize(Expression.Constant(1), unitValue: null), ex => Assert.AreEqual("unitValue", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => AnonymousTypeTupletizer.Tupletize(expression: null, Expression.Constant(1), excludeVisibleTypes: true), ex => Assert.AreEqual("expression", ex.ParamName)); AssertEx.ThrowsException <ArgumentNullException>(() => AnonymousTypeTupletizer.Tupletize(Expression.Constant(1), unitValue: null, excludeVisibleTypes: true), ex => Assert.AreEqual("unitValue", ex.ParamName)); }
public void AnonymousTypeTupletizer_Constant_NotSupported() { var e = (NewExpression)((Expression <Func <object> >)(() => new { a = 42, b = new[] { new { c = 42 } } })).Body; var arg0 = e.Arguments[0]; var arg1 = e.Arguments[1]; var a = e.Update(new Expression[] { arg0, Expression.Constant(arg1.Evaluate <object>(), arg1.Type) }); Assert.ThrowsException <InvalidOperationException>(() => _ = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null))); }
/// <summary> /// Normalizes the specified expression prior to submission to the service. /// </summary> /// <param name="expression">The expression to normalize.</param> /// <returns>The normalized expression.</returns> public override Expression Normalize(Expression expression) { // TODO: [IRP Core] Ordering of the rewrites (base/here; exposure of virtuals). // Runs a standard set of rewrites, causing callbacks to the Funcletize method below. var normalized = base.Normalize(expression); // Replaces compiler-generated anonymous types, e.g. for transparent identifiers, by tuples which don't need reconstruction in the service. var tupletized = AnonymousTypeTupletizer.Tupletize(normalized, Expression.Constant(null), excludeVisibleTypes: true); return(tupletized); }
public void AnonymousTypeTupletizer_Simple0() { Expression <Func <object> > f = () => new { }; var a = f.Body; var b = Expression.Constant(value: null); var t = AnonymousTypeTupletizer.Tupletize(a, b); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Constant_Simple2() { var x = new { a = 42, b = "bar" }; var a = Expression.Constant(x); var b = Expression.Constant(new Tuple <int, string>(42, "bar")); var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Constant_Simple9() { var x = new { a = 42, b = "bar", c = 12.34, d = false, e = 'a', f = 49.95m, g = 0.1f, h = (byte)128, i = new TimeSpan(1, 2, 3) }; var a = Expression.Constant(x); var b = Expression.Constant(new Tuple <int, string, double, bool, char, decimal, float, Tuple <byte, TimeSpan> >(42, "bar", 12.34, false, 'a', 49.95m, 0.1f, new Tuple <byte, TimeSpan>(128, new TimeSpan(1, 2, 3)))); var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Constant_Simple0() { var x = new { }; var a = Expression.Constant(x); var b = Expression.Constant("bar"); var t = AnonymousTypeTupletizer.Tupletize(a, b); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Constant_Null() { var x = new { a = 42 }; var a = Expression.Constant(value: null, x.GetType()); var b = Expression.Constant(value: null, typeof(Tuple <int>)); var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Simple10() { Expression <Func <object> > f = () => new { a = 42, b = "bar", c = 3.14, d = false, e = 49.95m, f = DateTime.Now, g = new TimeSpan(1, 2, 3), h = Guid.NewGuid(), i = (byte)128, j = 12.34f }; var a = f.Body; Expression <Func <object> > g = () => new Tuple <int, string, double, bool, decimal, DateTime, TimeSpan, Tuple <Guid, byte, float> >(42, "bar", 3.14, false, 49.95m, DateTime.Now, new TimeSpan(1, 2, 3), new Tuple <Guid, byte, float>(Guid.NewGuid(), 128, 12.34f)); var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Nested3() { Expression <Func <int> > f = () => new { a = new { b = new { a = new { b = 42 } } } }.a.b.a.b; var a = f.Body; Expression <Func <int> > g = () => new Tuple <Tuple <Tuple <Tuple <int> > > >(new Tuple <Tuple <Tuple <int> > >(new Tuple <Tuple <int> >(new Tuple <int>(42)))).Item1.Item1.Item1.Item1; var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Nested1() { Expression <Func <object> > f = () => new { a = 42, b = new { c = "bar", d = false }, e = 12.34, f = new { g = 'a' } }; var a = f.Body; Expression <Func <object> > g = () => new Tuple <int, Tuple <string, bool>, double, Tuple <char> >(42, new Tuple <string, bool>("bar", false), 12.34, new Tuple <char>('a')); var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_NoChange() { foreach (var e in new Expression[] { Expression.Constant(1), (Expression <Func <int> >)(() => DateTime.Now.Year), (Expression <Func <TimeSpan> >)(() => new TimeSpan(1, 2, 3)), (Expression <Func <IEnumerable <int>, IEnumerable <string> > >)(xs => from x in xs where x % 2 == 0 select x.ToString()) }) { var t = AnonymousTypeTupletizer.Tupletize(e, Expression.Constant(value: null)); Assert.AreSame(e, t); } }
public void AnonymousTypeTupletizer_Simple15_Accessor3() { Expression <Func <char> > f = () => new { a = 42, b = "bar", c = 3.14, d = false, e = 49.95m, f = DateTime.Now, g = new TimeSpan(1, 2, 3), h = Guid.NewGuid(), i = (byte)128, j = 12.34f, k = 24, l = true, m = "foo", n = (object)null, o = 'a' }.o; var a = f.Body; Expression <Func <char> > g = () => new Tuple <int, string, double, bool, decimal, DateTime, TimeSpan, Tuple <Guid, byte, float, int, bool, string, object, Tuple <char> > >(42, "bar", 3.14, false, 49.95m, DateTime.Now, new TimeSpan(1, 2, 3), new Tuple <Guid, byte, float, int, bool, string, object, Tuple <char> >(Guid.NewGuid(), 128, 12.34f, 24, true, "foo", null, new Tuple <char>('a'))).Rest.Rest.Item1; var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Simple8_Accessor2() { Expression <Func <Guid> > f = () => new { a = 42, b = "bar", c = 3.14, d = false, e = 49.95m, f = DateTime.Now, g = new TimeSpan(1, 2, 3), h = Guid.NewGuid() }.h; var a = f.Body; Expression <Func <Guid> > g = () => new Tuple <int, string, double, bool, decimal, DateTime, TimeSpan, Tuple <Guid> >(42, "bar", 3.14, false, 49.95m, DateTime.Now, new TimeSpan(1, 2, 3), new Tuple <Guid>(Guid.NewGuid())).Rest.Item1; var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Simple1_Accessor() { Expression <Func <int> > f = () => new { a = 42 }.a; var a = f.Body; Expression <Func <int> > g = () => new Tuple <int>(42).Item1; var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_Simple2() { Expression <Func <object> > f = () => new { a = 42, b = "bar" }; var a = f.Body; Expression <Func <object> > g = () => new Tuple <int, string>(42, "bar"); var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); }
public void AnonymousTypeTupletizer_NoChange() { foreach (var e in new Expression[] { Expression.Constant(1), #pragma warning disable IDE0004 // Remove Unnecessary Cast. (Only unnecessary on C# 10 or later.) (Expression <Func <int> >)(() => DateTime.Now.Year), (Expression <Func <TimeSpan> >)(() => new TimeSpan(1, 2, 3)), #pragma warning restore IDE0004 (Expression <Func <IEnumerable <int>, IEnumerable <string> > >)(xs => from x in xs where x % 2 == 0 select x.ToString()) }) { var t = AnonymousTypeTupletizer.Tupletize(e, Expression.Constant(value: null)); Assert.AreSame(e, t); } }
public void AnonymousTypeTupletizer_Simple2_ToString() { Expression <Func <string> > f = () => new { a = 42, b = "bar" }.ToString(); var a = f.Body; Expression <Func <string> > g = () => new Tuple <int, string>(42, "bar").ToString(); var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); Assert.AreEqual("{ a = 42, b = bar }", a.Evaluate <string>()); Assert.AreEqual("(42, bar)", b.Evaluate <string>()); Assert.AreEqual("(42, bar)", t.Evaluate <string>()); }
public void AnonymousTypeTupletizer_Simple2_GetHashCode() { Expression <Func <bool> > f = () => new { a = 42, b = "bar" }.GetHashCode() == new { a = 42, b = "bar" }.GetHashCode(); var a = f.Body; Expression <Func <bool> > g = () => new Tuple <int, string>(42, "bar").GetHashCode() == new Tuple <int, string>(42, "bar").GetHashCode(); var b = g.Body; var t = AnonymousTypeTupletizer.Tupletize(a, Expression.Constant(value: null)); var eq = new ExpressionEqualityComparer(); Assert.IsTrue(eq.Equals(b, t)); Assert.IsTrue(a.Evaluate <bool>()); Assert.IsTrue(b.Evaluate <bool>()); Assert.IsTrue(t.Evaluate <bool>()); }
public void AnonymousTypeTupletizer_ManOrBoy() { var expr = (from x in Enumerable.Empty <object>().AsQueryable() group x by x into g let a = g.OfType <bool>() let b = g.OfType <string>() let z = Enumerable.Zip(a, b, (x, y) => new { x, y }) from t in z select t.x ? t.y : "null") .Expression; var res = AnonymousTypeTupletizer.Tupletize(expr, Expression.Constant(value: null)); var csharp = CompilerGeneratedNameEliminator.Prettify(res).ToCSharpString(); Assert.AreEqual( StripWhitespace(@" __c0.GroupBy<object, object>((object x) => x) .Select<IGrouping<object, object>, Tuple<IGrouping<object, object>, IEnumerable<bool>>>( (IGrouping<object, object> g) => new Tuple<IGrouping<object, object>, IEnumerable<bool>>( g, g.OfType<bool>())) .Select<Tuple<IGrouping<object, object>, IEnumerable<bool>>, Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>>( (Tuple<IGrouping<object, object>, IEnumerable<bool>> t) => new Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>( t, t.Item1.OfType<string>())) .Select<Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>, Tuple<Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>, IEnumerable<Tuple<bool, string>>>>( (Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>> t) => new Tuple<Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>, IEnumerable<Tuple<bool, string>>>( t, t.Item1.Item2.Zip<bool, string, Tuple<bool, string>>( t.Item2, (bool x, string y) => new Tuple<bool, string>(x, y)))) .SelectMany<Tuple<Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>, IEnumerable<Tuple<bool, string>>>, Tuple<bool, string>, string>( (Tuple<Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>, IEnumerable<Tuple<bool, string>>> t) => t.Item2, (Tuple<Tuple<Tuple<IGrouping<object, object>, IEnumerable<bool>>, IEnumerable<string>>, IEnumerable<Tuple<bool, string>>> t, Tuple<bool, string> t0) => t0.Item1 ? t0.Item2 : ""null"")"), StripWhitespace(csharp) );
public override Expression Normalize(Expression expression) { // // NB: Typical Reaqtor clients talk to some service APIs on a front-end service that does // further analysis of the expression tree (after deserialization) prior to sending it // to one or more query evaluator nodes. For example, a query may get split to run across // multiple nodes. Here, we bind directly to the query engine, so a few more steps are // involved to make this happen: // // - The engine stores definitions in "tuple normal form" such that all operators can be // defined as unary. E.g. t => t.Item1.Where(t.Item2) rather than (xs, f) => xs.Where(f). // - The client refers to types in the IReactive*Proxy space with async APIs but the // engine has synchronous symmetric APIs in the IReactive* space. We map types across. // var normalized = base.Normalize(expression); var erased = AnonymousTypeTupletizer.Tupletize(normalized, Expression.Constant(null), excludeVisibleTypes: true); return(erased); }
public void ExpressionMemberAllowListScanner_ManOrBoyTest1() { var ws = new ExpressionMemberAllowListScanner { DeclaringTypes = { typeof(Queryable), typeof(string), typeof(int), typeof(Tuple <, >), } }; var e = (from x in new[] { 1, 2, 3 }.AsQueryable() where x > 0 let y = x * x let z = x.ToString() select z.ToUpper()) .Expression; e = AnonymousTypeTupletizer.Tupletize(e, Expression.Constant(value: null)); Assert.AreSame(e, ws.Visit(e)); }