diff --git a/src/Benchmark/Benchmark.csproj b/src/Benchmark/Benchmark.csproj
index 64bf338a..739dc721 100644
--- a/src/Benchmark/Benchmark.csproj
+++ b/src/Benchmark/Benchmark.csproj
@@ -19,14 +19,15 @@
-
+
-
-
+
+
+
diff --git a/src/Benchmark/Benchmarks/TestAll.cs b/src/Benchmark/Benchmarks/TestAll.cs
index 4b641334..40388f24 100644
--- a/src/Benchmark/Benchmarks/TestAll.cs
+++ b/src/Benchmark/Benchmarks/TestAll.cs
@@ -83,10 +83,10 @@ public void SetupFec()
[GlobalSetup(Target = nameof(CodegenTest))]
public void SetupCodegen()
{
- _fooInstance = TestAdaptHelper.SetupFooInstance();
- _customerInstance = TestAdaptHelper.SetupCustomerInstance();
- FooMapper.Map(_fooInstance);
- CustomerMapper.Map(_customerInstance);
+ //_fooInstance = TestAdaptHelper.SetupFooInstance();
+ //_customerInstance = TestAdaptHelper.SetupCustomerInstance();
+ //FooMapper.Map(_fooInstance);
+ //CustomerMapper.Map(_customerInstance);
}
[GlobalSetup(Target = nameof(ExpressMapperTest))]
diff --git a/src/Benchmark/Benchmarks/TestComplexTypes.cs b/src/Benchmark/Benchmarks/TestComplexTypes.cs
index 048128b8..971f2e73 100644
--- a/src/Benchmark/Benchmarks/TestComplexTypes.cs
+++ b/src/Benchmark/Benchmarks/TestComplexTypes.cs
@@ -70,8 +70,8 @@ public void SetupFec()
[GlobalSetup(Target = nameof(CodegenTest))]
public void SetupCodegen()
{
- _customerInstance = TestAdaptHelper.SetupCustomerInstance();
- CustomerMapper.Map(_customerInstance);
+ //_customerInstance = TestAdaptHelper.SetupCustomerInstance();
+ //CustomerMapper.Map(_customerInstance);
}
[GlobalSetup(Target = nameof(ExpressMapperTest))]
diff --git a/src/Benchmark/Benchmarks/TestSimpleTypes.cs b/src/Benchmark/Benchmarks/TestSimpleTypes.cs
index bc96def0..7c832a56 100644
--- a/src/Benchmark/Benchmarks/TestSimpleTypes.cs
+++ b/src/Benchmark/Benchmarks/TestSimpleTypes.cs
@@ -71,8 +71,8 @@ public void SetupFec()
[GlobalSetup(Target = nameof(CodegenTest))]
public void SetupCodegen()
{
- _fooInstance = TestAdaptHelper.SetupFooInstance();
- FooMapper.Map(_fooInstance);
+ //_fooInstance = TestAdaptHelper.SetupFooInstance();
+ //FooMapper.Map(_fooInstance);
}
[GlobalSetup(Target = nameof(ExpressMapperTest))]
diff --git a/src/Benchmark/TestAdaptHelper.cs b/src/Benchmark/TestAdaptHelper.cs
index 107915c6..3d7db0eb 100644
--- a/src/Benchmark/TestAdaptHelper.cs
+++ b/src/Benchmark/TestAdaptHelper.cs
@@ -88,7 +88,7 @@ public static void ConfigureMapster(Foo fooInstance, MapsterCompilerType type)
}
public static void ConfigureExpressMapper(Foo fooInstance)
{
- ExpressMapper.Mapper.Map(fooInstance); //exercise
+ //ExpressMapper.Mapper.Map(fooInstance); //exercise
}
public static void ConfigureAutoMapper(Foo fooInstance)
{
@@ -103,7 +103,7 @@ public static void ConfigureMapster(Customer customerInstance, MapsterCompilerTy
}
public static void ConfigureExpressMapper(Customer customerInstance)
{
- ExpressMapper.Mapper.Map(customerInstance); //exercise
+ //ExpressMapper.Mapper.Map(customerInstance); //exercise
}
public static void ConfigureAutoMapper(Customer customerInstance)
{
@@ -121,7 +121,7 @@ public static void TestExpressMapper(TSrc item, int iterations)
where TSrc : class
where TDest : class, new()
{
- Loop(item, get => ExpressMapper.Mapper.Map(get), iterations);
+ //Loop(item, get => ExpressMapper.Mapper.Map(get), iterations);
}
public static void TestAutoMapper(TSrc item, int iterations)
@@ -133,12 +133,12 @@ public static void TestAutoMapper(TSrc item, int iterations)
public static void TestCodeGen(Foo item, int iterations)
{
- Loop(item, get => FooMapper.Map(get), iterations);
+ //Loop(item, get => FooMapper.Map(get), iterations);
}
public static void TestCodeGen(Customer item, int iterations)
{
- Loop(item, get => CustomerMapper.Map(get), iterations);
+ //Loop(item, get => CustomerMapper.Map(get), iterations);
}
private static void Loop(T item, Action action, int iterations)
diff --git a/src/ExpressionDebugger.Console/ExpressionDebugger.Console.csproj b/src/ExpressionDebugger.Console/ExpressionDebugger.Console.csproj
new file mode 100644
index 00000000..e7fd22a3
--- /dev/null
+++ b/src/ExpressionDebugger.Console/ExpressionDebugger.Console.csproj
@@ -0,0 +1,15 @@
+
+
+
+ Exe
+ net6.0
+ true
+
+
+
+
+
+
+
+
+
diff --git a/src/ExpressionDebugger.Console/Program.cs b/src/ExpressionDebugger.Console/Program.cs
new file mode 100644
index 00000000..23268676
--- /dev/null
+++ b/src/ExpressionDebugger.Console/Program.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Linq.Expressions;
+
+namespace ExpressionDebugger.Console
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var p1 = Expression.Parameter(typeof(int));
+ var p2 = Expression.Parameter(typeof(int));
+ var body = Expression.Add(p1, Expression.Block(
+ new Expression[] {
+ Expression.Call(typeof(System.Console).GetMethod("WriteLine", new [] { typeof(int) }), p2),
+ p2,
+ }));
+ var lambda = Expression.Lambda>(body, p1, p2);
+
+ var script = lambda.ToScript();
+
+ var fun = lambda.CompileWithDebugInfo();
+ var result = fun(1, 2);
+ System.Console.WriteLine(result);
+ }
+ }
+}
diff --git a/src/ExpressionDebugger.Tests/DebugInfoInjectorTest.cs b/src/ExpressionDebugger.Tests/DebugInfoInjectorTest.cs
new file mode 100644
index 00000000..a18711b7
--- /dev/null
+++ b/src/ExpressionDebugger.Tests/DebugInfoInjectorTest.cs
@@ -0,0 +1,821 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace ExpressionDebugger.Tests
+{
+ [TestClass]
+ public class DebugInfoInjectorTest
+ {
+ [TestMethod]
+ public void TestBinary()
+ {
+ Expression> fn = (a, b) => a + b;
+ var str = fn.ToScript();
+
+ var expected = @"
+public int Main(int a, int b)
+{
+ return a + b;
+}".Trim();
+
+ // Well, in Visual Studio (at bottom of the code editor, you should be sure to have "CRLF" for the DebugInfoInjectorTest.cs file)
+ // if not, you may have problem comparing \r\n with \n.
+ var r = str.Equals(expected);
+
+ Assert.AreEqual(expected, str);
+ }
+
+ [TestMethod]
+ public void TestBinary_PowerAssign()
+ {
+ var exp = Expression.PowerAssign(Expression.Variable(typeof(double), "d"), Expression.Constant(2d));
+ var str = exp.ToScript();
+ Assert.AreEqual("d = Math.Pow(d, 2d)", str);
+ }
+
+ [TestMethod]
+ public void TestBinary_ArrayIndex()
+ {
+ Expression> fn = a => a[0];
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(int[] a)
+{
+ return a[0];
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestBlock()
+ {
+ var p1 = Expression.Variable(typeof(int));
+ var block = Expression.Block(new[] { p1 }, Expression.Add(p1, p1));
+ var str = block.ToScript();
+ Assert.AreEqual(@"
+int p1;
+
+p1 + p1;".Trim(), str);
+ }
+
+ [TestMethod]
+ public void Test_Conditional()
+ {
+ Expression> fn = a => a < 0 ? a - 1 : a + 1;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(int a)
+{
+ return a < 0 ? a - 1 : a + 1;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestConditional_Block()
+ {
+ var exp = Expression.Condition(
+ Expression.Equal(Expression.Constant(1), Expression.Constant(2)),
+ Expression.Constant(4),
+ Expression.Constant(3),
+ typeof(void));
+ var str = exp.ToScript();
+ Assert.AreEqual(@"
+if (1 == 2)
+{
+ 4;
+}
+else
+{
+ 3;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestConditional_Block_Chain()
+ {
+ var exp = Expression.Condition(
+ Expression.Equal(Expression.Constant(1), Expression.Constant(2)),
+ Expression.Constant(4),
+ Expression.Condition(
+ Expression.Equal(Expression.Constant(5), Expression.Constant(6)),
+ Expression.Constant(3),
+ Expression.Constant(2),
+ typeof(void)),
+ typeof(void));
+ var str = exp.ToScript();
+ Assert.AreEqual(@"
+if (1 == 2)
+{
+ 4;
+}
+else if (5 == 6)
+{
+ 3;
+}
+else
+{
+ 2;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestConstants()
+ {
+ Expression> fn = s => s == "x" || s == @"\" || s == null || s.IsNormalized() == false || s.GetType() == typeof(string) ? 'x' : s[0];
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public char Main(string s)
+{
+ return s == ""x"" || s == @""\"" || s == null || s.IsNormalized() == false || s.GetType() == typeof(string) ? 'x' : s[0];
+}".Trim()
+ , str);
+
+ Expression> fn2 = () => 1f.ToString() + 2m.ToString() + ((byte)1).ToString() + DayOfWeek.Friday.ToString() + default(DateTime).ToString();
+ var str2 = fn2.ToScript();
+ Assert.AreEqual(@"
+public string Main()
+{
+ return 1f.ToString() + 2m.ToString() + ((byte)1).ToString() + DayOfWeek.Friday.ToString() + default(DateTime).ToString();
+}".Trim()
+ , str2);
+ }
+
+ [TestMethod]
+ public void TestConstant_DateTime()
+ {
+ var now = DateTime.Now;
+ var expr = Expression.Constant(now);
+ var script = expr.ToScript();
+ Assert.AreEqual(@"
+private DateTime DateTime1;
+DateTime1".Trim(), script);
+ }
+
+// [TestMethod]
+// public void TestDynamic()
+// {
+// var dynType = typeof(ExpandoObject);
+// var p1 = Expression.Variable(dynType);
+// var line1 = Expression.Dynamic(Binder.Convert(CSharpBinderFlags.None, typeof(Poco), dynType), typeof(object), p1);
+// var line2 = Expression.Dynamic(Binder.GetMember(CSharpBinderFlags.None, "Blah", dynType,
+// new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }), typeof(object), p1);
+// var line3 = Expression.Dynamic(Binder.SetMember(CSharpBinderFlags.None, "Blah", dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1, Expression.Constant(0));
+// var line4 = Expression.Dynamic(Binder.GetIndex(CSharpBinderFlags.None, dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1, Expression.Constant(1));
+// var line5 = Expression.Dynamic(Binder.SetIndex(CSharpBinderFlags.None, dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1, Expression.Constant(1), Expression.Constant(0));
+// var line6 = Expression.Dynamic(Binder.InvokeMember(CSharpBinderFlags.None, "Blah", null, dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1, Expression.Constant(2));
+// var line7 = Expression.Dynamic(Binder.Invoke(CSharpBinderFlags.None, dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1, Expression.Constant(2));
+// var line8 = Expression.Dynamic(Binder.UnaryOperation(CSharpBinderFlags.None, ExpressionType.Negate, dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1);
+// var line9 = Expression.Dynamic(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Add, dynType,
+// new[]
+// {
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+// }), typeof(object), p1, Expression.Constant(3));
+// var expr = Expression.Block(new[] { p1 }, line1, line2, line3, line4, line5, line6, line7, line8, line9);
+// var str = expr.ToScript();
+// Assert.AreEqual(@"
+//dynamic p1;
+
+//(Poco)p1;
+//p1.Blah;
+//p1.Blah = 0;
+//p1[1];
+//p1[1] = 0;
+//p1.Blah(2);
+//p1(2);
+//-p1;
+//p1 + 3;"
+// , str);
+// }
+
+ [TestMethod]
+ public void TestDefault()
+ {
+ var exp = Expression.Default(typeof(int));
+ var str = exp.ToScript();
+ Assert.AreEqual("default(int)", str);
+ }
+
+ [TestMethod]
+ public void TestGroup()
+ {
+ Expression> fn = x => -(-x) + 1 + x - (1 - x);
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(int x)
+{
+ return -(-x) + 1 + x - (1 - x);
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestGroup_MultiLine()
+ {
+ var p = Expression.Variable(typeof(int), "p");
+ var exp = Expression.Add(
+ p,
+ Expression.Block(
+ new Expression[] {
+ Expression.Call(typeof(Console).GetMethod(nameof(Console.WriteLine), new [] { typeof(int) }), p),
+ p,
+ }
+ ));
+ var str = exp.ToScript();
+ Assert.AreEqual(@"p + (new Func(() => {
+ Console.WriteLine(p);
+ return p;
+}))()"
+ , str);
+ }
+
+ [TestMethod]
+ public void TestIndex()
+ {
+ var p1 = Expression.Parameter(typeof(int[]));
+ var expr = Expression.MakeIndex(p1, null, new[] { Expression.Constant(1) });
+ var str = expr.ToScript();
+ Assert.AreEqual("p1[1]", str);
+ }
+
+ [TestMethod]
+ public void TestLambda()
+ {
+ var p1 = Expression.Parameter(typeof(int));
+ var func1 = Expression.Lambda(
+ Expression.Increment(p1),
+ p1);
+ var expr = Expression.Block(
+ Expression.Add(
+ Expression.Invoke(func1, Expression.Constant(1)),
+ Expression.Invoke(func1, Expression.Constant(1))));
+ var str = expr.ToScript();
+ Assert.AreEqual(@"
+func1(1) + func1(1);
+
+private int func1(int p1)
+{
+ return p1 + 1;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestLambda_Inline()
+ {
+ Expression, IQueryable>> fn = q => q.Where(it => it > 0);
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public IQueryable Main(IQueryable q)
+{
+ return q.Where(it => it > 0);
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestListInit()
+ {
+ Expression>> list = () => new List() { 1, 2, 3 };
+ var str = list.ToScript();
+ Assert.AreEqual(@"
+public List Main()
+{
+ return new List() {1, 2, 3};
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestListInit_Dictionary()
+ {
+ Expression>> list = () => new Dictionary()
+ {
+ {1, 2},
+ {3, 4}
+ };
+ var str = list.ToScript();
+ Assert.AreEqual(@"
+public Dictionary Main()
+{
+ return new Dictionary() {{1, 2}, {3, 4}};
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestLoop()
+ {
+ var @break = Expression.Label();
+ var @continue = Expression.Label();
+ var @return = Expression.Label();
+ var p1 = Expression.Parameter(typeof(int));
+ var expr = Expression.Loop(
+ Expression.Condition(
+ Expression.GreaterThanOrEqual(p1, Expression.Constant(1)),
+ Expression.Condition(
+ Expression.Equal(p1, Expression.Constant(1)),
+ Expression.Return(@return, p1),
+ Expression.Block(
+ Expression.PostDecrementAssign(p1),
+ Expression.Continue(@continue))),
+ Expression.Break(@break)),
+ @break,
+ @continue);
+
+ var str = expr.ToScript();
+ Assert.AreEqual(@"
+while (p1 >= 1)
+{
+ if (p1 == 1)
+ {
+ return p1;
+ }
+ else
+ {
+ p1--;
+ continue;
+ }
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestLoop2()
+ {
+ var label = Expression.Label();
+ var expr = Expression.Block(
+ Expression.Loop(Expression.Goto(label)),
+ Expression.Label(label));
+ var str = expr.ToScript();
+ Assert.AreEqual(@"
+while (true)
+{
+ goto label1;
+}
+label1:".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestMemberAccess()
+ {
+ Expression> fn = () => DateTime.Now.Day;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main()
+{
+ return DateTime.Now.Day;
+}".Trim()
+ , str);
+ }
+
+ private class Poco
+ {
+ public string Name { get; set; }
+ public Poco Parent { get; } = new Poco();
+ public List Children { get; } = new List();
+ }
+
+ [TestMethod]
+ public void TestMemberInit()
+ {
+ Expression> fn = () => new Poco()
+ {
+ Name = "1",
+ Parent = { Name = "2" },
+ Children = { new Poco(), new Poco() }
+ };
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public DebugInfoInjectorTest.Poco Main()
+{
+ return new DebugInfoInjectorTest.Poco()
+ {
+ Name = ""1"",
+ Parent = {Name = ""2""},
+ Children = {new DebugInfoInjectorTest.Poco(), new DebugInfoInjectorTest.Poco()}
+ };
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestMethodCall_Default()
+ {
+ Expression, int>> fn = dict => dict[0];
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(Dictionary dict)
+{
+ return dict[0];
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestMethodCall()
+ {
+ Expression, string>> fn = list => list.ToString();
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public string Main(List list)
+{
+ return list.ToString();
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestMethodCall_Static()
+ {
+ Expression> fn = (a, b) => Math.Max(a, b);
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(int a, int b)
+{
+ return Math.Max(a, b);
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestNewArray()
+ {
+ Expression> fn = i => new[] { i };
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int[] Main(int i)
+{
+ return new int[] {i};
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestNewArray_Bound()
+ {
+ Expression> fn = i => new int[i];
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int[] Main(int i)
+{
+ return new int[i];
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestParameter_Reserved()
+ {
+ Expression> fn = @null => @null.Value;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(int? @null)
+{
+ return @null.Value;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestSwitch()
+ {
+ var p1 = Expression.Parameter(typeof(int));
+ var expr = Expression.Switch(
+ p1,
+ Expression.Constant(0),
+ Expression.SwitchCase(Expression.Constant(1), Expression.Constant(1)));
+ var str = expr.ToScript();
+ Assert.AreEqual(@"
+switch (p1)
+{
+ case 1:
+ 1;
+ break;
+ default:
+ 0;
+ break;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestTryCatch()
+ {
+ var p1 = Expression.Parameter(typeof(double));
+ var tryCatch = Expression.TryCatchFinally(
+ Expression.Block(
+ typeof(void),
+ Expression.Assign(
+ p1,
+ Expression.Divide(Expression.Constant(1.0), Expression.Constant(0.0)))),
+ Expression.Throw(Expression.New(typeof(NotSupportedException))),
+ Expression.Catch(
+ Expression.Parameter(typeof(DivideByZeroException)),
+ Expression.Rethrow(),
+ Expression.Constant(true)));
+ var str = tryCatch.ToScript();
+ Assert.AreEqual(@"
+try
+{
+ p1 = 1d / 0d;
+}
+catch (DivideByZeroException p2) when (true)
+{
+ throw;
+}
+finally
+{
+ throw new NotSupportedException();
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestTryFault()
+ {
+ var expr = Expression.TryFault(
+ Expression.Constant(1),
+ Expression.Constant("blah"));
+ var str = expr.ToScript();
+ Assert.AreEqual(@"
+bool fault1 = true;
+try
+{
+ 1;
+ fault1 = false;
+}
+finally
+{
+ if (fault1)
+ {
+ ""blah"";
+ }
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestTypeBinary()
+ {
+ Expression> fn = o => o is Array;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public bool Main(object o)
+{
+ return o is Array;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestUnary_Convert()
+ {
+ Expression> fn = d => (int)d;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(double d)
+{
+ return (int)d;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestUnary_ArrayLength()
+ {
+ Expression> fn = a => a.Length;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public int Main(int[] a)
+{
+ return a.Length;
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestUnary_As()
+ {
+ Expression> fn = expr => expr as UnaryExpression;
+ var str = fn.ToScript();
+ Assert.AreEqual(@"
+public Expression Main(Expression expr)
+{
+ return expr as UnaryExpression;
+}".Trim()
+ , str);
+ }
+
+ internal static int GetInternal() => 1;
+
+ [TestMethod]
+ public void TestToString()
+ {
+ var call = Expression.Call(
+ typeof(DebugInfoInjectorTest).GetMethod(nameof(GetInternal),
+ BindingFlags.Static | BindingFlags.NonPublic)
+ );
+ var exp = Expression.Lambda>(call);
+ var str = exp.ToScript(new ExpressionDefinitions
+ {
+ IsStatic = true,
+ MethodName = "Main",
+ Namespace = "ExpressionDebugger.Tests",
+ TypeName = "MockClass"
+ });
+ Assert.AreEqual(@"
+using System;
+
+namespace ExpressionDebugger.Tests
+{
+ public static partial class MockClass
+ {
+ private static Func GetInternal1;
+
+ public static int Main()
+ {
+ return GetInternal1.Invoke();
+ }
+ }
+}".Trim()
+ , str);
+ }
+
+ [TestMethod]
+ public void TestExpression()
+ {
+ Expression> lambda = data => new Data {Id = data.Id + "1", Records = data.Records.Select(it => it + 1)};
+ var str = lambda.ToScript(new ExpressionDefinitions {IsExpression = true});
+ Assert.AreEqual(@"
+public Expression> Main => data => new DebugInfoInjectorTest.Data()
+{
+ Id = data.Id + ""1"",
+ Records = data.Records.Select(it => it + 1)
+};".Trim(), str);
+ }
+
+ [TestMethod]
+ public void TestExtensionMethod()
+ {
+ var p1 = Expression.Parameter(typeof(int));
+ var p2 = Expression.Parameter(typeof(int));
+ var lambda = Expression.Lambda>(
+ Expression.Add(p1, p2),
+ p1, p2);
+ var translator = new ExpressionTranslator(new TypeDefinitions
+ {
+ IsStatic = true,
+ Namespace = "ExpressionDebugger.Tests",
+ TypeName = "MockClass"
+ });
+ translator.VisitLambda(lambda, ExpressionTranslator.LambdaType.ExtensionMethod, "Add");
+ var str = translator.ToString();
+ Assert.AreEqual(@"
+namespace ExpressionDebugger.Tests
+{
+ public static partial class MockClass
+ {
+ public static int Add(this int p1, int p2)
+ {
+ return p1 + p2;
+ }
+ }
+}".Trim(), str);
+ }
+
+ [TestMethod]
+ public void TestProperties()
+ {
+ var translator = new ExpressionTranslator(new TypeDefinitions
+ {
+ IsStatic = false,
+ Namespace = "ExpressionDebugger.Tests",
+ TypeName = "MockClass",
+ NullableContext = 2,
+ });
+ translator.Properties.Add(new PropertyDefinitions
+ {
+ Name = "Prop1",
+ Type = typeof(string),
+ NullableContext = 0,
+ });
+ translator.Properties.Add(new PropertyDefinitions
+ {
+ Name = "Prop2",
+ Type = typeof(List>),
+ IsReadOnly = true,
+ Nullable = new byte[] { 1, 2, 1, 2 }
+ });
+ translator.Properties.Add(new PropertyDefinitions
+ {
+ Name = "Prop3",
+ Type = typeof(string),
+ IsInitOnly = true,
+ NullableContext = 0,
+ });
+ var str = translator.ToString();
+ Assert.AreEqual(@"
+using System.Collections.Generic;
+
+namespace ExpressionDebugger.Tests
+{
+ public partial class MockClass
+ {
+ public string Prop1 { get; set; }
+ public List?> Prop2 { get; }
+ public string Prop3 { get; init; }
+
+ public MockClass(List?> prop2)
+ {
+ this.Prop2 = prop2;
+ }
+ }
+}".Trim(), str);
+ }
+
+
+ [TestMethod]
+ public void TestRecordType()
+ {
+ var translator = new ExpressionTranslator(new TypeDefinitions
+ {
+ IsStatic = false,
+ Namespace = "ExpressionDebugger.Tests",
+ TypeName = "MockClass",
+ IsRecordType = true,
+ });
+ translator.Properties.Add(new PropertyDefinitions
+ {
+ Name = "Prop1",
+ Type = typeof(string)
+ });
+ translator.Properties.Add(new PropertyDefinitions
+ {
+ Name = "Prop2",
+ Type = typeof(string),
+ IsReadOnly = true
+ });
+ translator.Properties.Add(new PropertyDefinitions
+ {
+ Name = "Prop3",
+ Type = typeof(string),
+ IsInitOnly = true
+ });
+ var str = translator.ToString();
+ Assert.AreEqual(@"
+namespace ExpressionDebugger.Tests
+{
+ public partial record MockClass(string prop2)
+ {
+ public string Prop1 { get; set; }
+ public string Prop3 { get; init; }
+ }
+}".Trim(), str);
+ }
+
+ public class Data
+ {
+ public string Id { get; set; }
+ public IEnumerable Records { get; set; }
+ }
+ }
+}
diff --git a/src/ExpressionDebugger.Tests/ExpressionDebugger.Tests.csproj b/src/ExpressionDebugger.Tests/ExpressionDebugger.Tests.csproj
new file mode 100644
index 00000000..657fc325
--- /dev/null
+++ b/src/ExpressionDebugger.Tests/ExpressionDebugger.Tests.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ExpressionDebugger.sln b/src/ExpressionDebugger.sln
new file mode 100644
index 00000000..6b4b8d45
--- /dev/null
+++ b/src/ExpressionDebugger.sln
@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.4
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionDebugger", "ExpressionDebugger\ExpressionDebugger.csproj", "{A9B56FC4-B2BC-4A32-B1C0-B926F6259666}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionDebugger.Tests", "ExpressionDebugger.Tests\ExpressionDebugger.Tests.csproj", "{024FB14F-7B40-42E4-8B80-1D348914124C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionDebugger.Console", "ExpressionDebugger.Console\ExpressionDebugger.Console.csproj", "{71E2EC60-6780-4AB8-9773-91B4939560FB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionTranslator", "ExpressionTranslator\ExpressionTranslator.csproj", "{9B67882F-BE07-45C9-9B86-FB33A8B4EA5B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A9B56FC4-B2BC-4A32-B1C0-B926F6259666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A9B56FC4-B2BC-4A32-B1C0-B926F6259666}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A9B56FC4-B2BC-4A32-B1C0-B926F6259666}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A9B56FC4-B2BC-4A32-B1C0-B926F6259666}.Release|Any CPU.Build.0 = Release|Any CPU
+ {024FB14F-7B40-42E4-8B80-1D348914124C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {024FB14F-7B40-42E4-8B80-1D348914124C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {024FB14F-7B40-42E4-8B80-1D348914124C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {024FB14F-7B40-42E4-8B80-1D348914124C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {71E2EC60-6780-4AB8-9773-91B4939560FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {71E2EC60-6780-4AB8-9773-91B4939560FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {71E2EC60-6780-4AB8-9773-91B4939560FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {71E2EC60-6780-4AB8-9773-91B4939560FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9B67882F-BE07-45C9-9B86-FB33A8B4EA5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9B67882F-BE07-45C9-9B86-FB33A8B4EA5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9B67882F-BE07-45C9-9B86-FB33A8B4EA5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9B67882F-BE07-45C9-9B86-FB33A8B4EA5B}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/ExpressionDebugger/ExpressionCompilationOptions.cs b/src/ExpressionDebugger/ExpressionCompilationOptions.cs
new file mode 100644
index 00000000..6bab44fc
--- /dev/null
+++ b/src/ExpressionDebugger/ExpressionCompilationOptions.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace ExpressionDebugger
+{
+ public class ExpressionCompilationOptions
+ {
+ public ExpressionDefinitions? DefaultDefinitions { get; set; }
+ public IEnumerable? References { get; set; }
+ public bool EmitFile { get; set; }
+ public string? RootPath { get; set; }
+ public bool? IsRelease { get; set; }
+ public bool ThrowOnFailedCompilation { get; set; }
+ }
+}
diff --git a/src/ExpressionDebugger/ExpressionCompiler.cs b/src/ExpressionDebugger/ExpressionCompiler.cs
new file mode 100644
index 00000000..2f9203de
--- /dev/null
+++ b/src/ExpressionDebugger/ExpressionCompiler.cs
@@ -0,0 +1,136 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Emit;
+using Microsoft.CodeAnalysis.Text;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Text;
+
+namespace ExpressionDebugger
+{
+ public class ExpressionCompiler
+ {
+ public List Translators { get; } = new List();
+
+ private readonly ExpressionCompilationOptions? _options;
+ public ExpressionCompiler(ExpressionCompilationOptions? options = null)
+ {
+ _options = options;
+ }
+
+ private readonly List _codes = new List();
+ public void AddFile(string code, string filename)
+ {
+ var buffer = Encoding.UTF8.GetBytes(code);
+
+ var path = filename;
+ if (_options?.EmitFile == true)
+ {
+ var root = _options?.RootPath
+ ?? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "GeneratedSources");
+ Directory.CreateDirectory(root);
+ path = Path.Combine(root, filename);
+ using var fs = new FileStream(path, FileMode.Create);
+ fs.Write(buffer, 0, buffer.Length);
+ }
+
+ var sourceText = SourceText.From(buffer, buffer.Length, Encoding.UTF8, canBeEmbedded: true);
+
+ var syntaxTree = CSharpSyntaxTree.ParseText(
+ sourceText,
+ new CSharpParseOptions(),
+ path);
+
+ var syntaxRootNode = syntaxTree.GetRoot() as CSharpSyntaxNode;
+ var encoded = CSharpSyntaxTree.Create(syntaxRootNode, null, path, Encoding.UTF8);
+ _codes.Add(encoded);
+ }
+
+ public void AddFile(LambdaExpression node, ExpressionDefinitions? definitions = null)
+ {
+ definitions ??= _options?.DefaultDefinitions ?? new ExpressionDefinitions {IsStatic = true};
+ definitions.TypeName ??= "Program";
+
+ var translator = ExpressionTranslator.Create(node, definitions);
+ var script = translator.ToString();
+ Translators.Add(translator);
+
+ this.AddFile(script, Path.ChangeExtension(Path.GetRandomFileName(), ".cs"));
+ }
+
+ public Assembly CreateAssembly()
+ {
+ var references = new HashSet();
+ references.UnionWith(from t in Translators
+ from n in t.TypeNames
+ select n.Key.Assembly);
+
+ if (_options?.References != null)
+ references.UnionWith(_options.References);
+ references.Add(typeof(object).Assembly);
+
+#if NETSTANDARD2_0 || NET6_0_OR_GREATER
+ references.Add(Assembly.Load(new AssemblyName("netstandard")));
+ references.Add(Assembly.Load(new AssemblyName("System.Runtime")));
+ references.Add(Assembly.Load(new AssemblyName("System.Collections")));
+#endif
+
+ var assemblyName = Path.GetRandomFileName();
+ var symbolsName = Path.ChangeExtension(assemblyName, "pdb");
+
+ var metadataReferences = references.Select(it => MetadataReference.CreateFromFile(it.Location));
+ var isRelease = _options?.IsRelease ?? !Debugger.IsAttached;
+ CSharpCompilation compilation = CSharpCompilation.Create(
+ assemblyName,
+ _codes,
+ metadataReferences,
+ new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, usings: new[] { "System" })
+ .WithOptimizationLevel(isRelease ? OptimizationLevel.Release : OptimizationLevel.Debug)
+ .WithPlatform(Platform.AnyCpu)
+ );
+
+ using var assemblyStream = new MemoryStream();
+ using var symbolsStream = new MemoryStream();
+ var emitOptions = new EmitOptions(
+ debugInformationFormat: DebugInformationFormat.PortablePdb,
+ pdbFilePath: symbolsName);
+
+ var embeddedTexts = _codes.Select(it => EmbeddedText.FromSource(it.FilePath, it.GetText()));
+
+ EmitResult result = compilation.Emit(
+ peStream: assemblyStream,
+ pdbStream: symbolsStream,
+ embeddedTexts: embeddedTexts,
+ options: emitOptions);
+
+ if (!result.Success)
+ {
+ var errors = new List();
+
+ IEnumerable failures = result.Diagnostics.Where(diagnostic =>
+ diagnostic.IsWarningAsError ||
+ diagnostic.Severity == DiagnosticSeverity.Error);
+
+ foreach (Diagnostic diagnostic in failures)
+ errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}");
+
+ throw new InvalidOperationException(string.Join("\n", errors));
+ }
+
+ assemblyStream.Seek(0, SeekOrigin.Begin);
+ symbolsStream.Seek(0, SeekOrigin.Begin);
+
+#if NETSTANDARD2_0 || NET6_0_OR_GREATER
+ return System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(assemblyStream, symbolsStream);
+#else
+ return Assembly.Load(assemblyStream.ToArray(), symbolsStream.ToArray());
+#endif
+ }
+
+ }
+}
diff --git a/src/ExpressionDebugger/ExpressionDebugger.csproj b/src/ExpressionDebugger/ExpressionDebugger.csproj
new file mode 100644
index 00000000..df9357e4
--- /dev/null
+++ b/src/ExpressionDebugger/ExpressionDebugger.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net6.0
+ True
+ Chaowlert Chaisrichalermpol
+ Step into debugging from linq expressions
+ https://github.com/chaowlert/ExpressionDebugger
+ https://github.com/chaowlert/ExpressionDebugger
+ expression;linq;debug
+ https://cloud.githubusercontent.com/assets/5763993/26522656/41e28a6e-432f-11e7-9cae-7856f927d1a1.png
+ True
+ true
+ ExpressionDebugger.snk
+ 2.2.0
+ https://github.com/chaowlert/ExpressionDebugger/blob/master/LICENSE
+ 8.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ExpressionDebugger/ExpressionDebugger.snk b/src/ExpressionDebugger/ExpressionDebugger.snk
new file mode 100644
index 00000000..b7f3c897
Binary files /dev/null and b/src/ExpressionDebugger/ExpressionDebugger.snk differ
diff --git a/src/ExpressionDebugger/ExpressionDebuggerExtensions.cs b/src/ExpressionDebugger/ExpressionDebuggerExtensions.cs
new file mode 100644
index 00000000..29d2bae0
--- /dev/null
+++ b/src/ExpressionDebugger/ExpressionDebuggerExtensions.cs
@@ -0,0 +1,62 @@
+using ExpressionDebugger;
+using System.Diagnostics;
+using System.Reflection;
+
+// ReSharper disable once CheckNamespace
+namespace System.Linq.Expressions
+{
+ public static class ExpressionDebuggerExtensions
+ {
+
+ ///
+ /// Compile with debugging info injected
+ ///
+ /// Type of lambda expression
+ /// Lambda expression
+ /// Compilation options
+ /// Generated method
+ public static T CompileWithDebugInfo(this Expression node, ExpressionCompilationOptions? options = null)
+ {
+ return (T)(object)CompileWithDebugInfo((LambdaExpression)node, options);
+ }
+
+ public static Delegate CompileWithDebugInfo(this LambdaExpression node, ExpressionCompilationOptions? options = null)
+ {
+ try
+ {
+ var compiler = new ExpressionCompiler(options);
+ compiler.AddFile(node);
+ var assembly = compiler.CreateAssembly();
+
+ var translator = compiler.Translators[0];
+ return translator.CreateDelegate(assembly);
+ }
+ catch (Exception ex)
+ {
+ if (options?.ThrowOnFailedCompilation == true)
+ throw;
+ Debug.Print(ex.ToString());
+ return node.Compile();
+ }
+ }
+
+ public static Delegate CreateDelegate(this ExpressionTranslator translator, Assembly assembly)
+ {
+ var definitions = translator.Definitions!;
+ var typeName = definitions.Namespace == null
+ ? definitions.TypeName
+ : definitions.Namespace + "." + definitions.TypeName;
+ var type = assembly.GetType(typeName);
+ var main = translator.Methods.First();
+ var method = type.GetMethod(main.Key)!;
+ var obj = definitions.IsStatic ? null : Activator.CreateInstance(type);
+ var flag = definitions.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
+ foreach (var kvp in translator.Constants)
+ {
+ var field = type.GetField(kvp.Value, BindingFlags.NonPublic | flag)!;
+ field.SetValue(obj, kvp.Key);
+ }
+ return method.CreateDelegate(main.Value, obj);
+ }
+ }
+}
diff --git a/src/ExpressionTranslator/ExpressionDefinitions.cs b/src/ExpressionTranslator/ExpressionDefinitions.cs
new file mode 100644
index 00000000..165d679d
--- /dev/null
+++ b/src/ExpressionTranslator/ExpressionDefinitions.cs
@@ -0,0 +1,8 @@
+namespace ExpressionDebugger
+{
+ public class ExpressionDefinitions : TypeDefinitions
+ {
+ public string? MethodName { get; set; }
+ public bool IsExpression { get; set; }
+ }
+}
diff --git a/src/ExpressionTranslator/ExpressionTranslator.cs b/src/ExpressionTranslator/ExpressionTranslator.cs
new file mode 100644
index 00000000..5e018e14
--- /dev/null
+++ b/src/ExpressionTranslator/ExpressionTranslator.cs
@@ -0,0 +1,2029 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+#if !NETSTANDARD1_3
+using System.Dynamic;
+#endif
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace ExpressionDebugger
+{
+ public class ExpressionTranslator : ExpressionVisitor
+ {
+ private const int Tabsize = 4;
+ private StringWriter _writer;
+ private int _indentLevel;
+ private List? _appendWriters;
+
+ private HashSet? _usings;
+ private Dictionary? _defaults;
+
+ private Dictionary
-
-
+
+
diff --git a/src/Mapster.Tests/Mapster.Tests.csproj b/src/Mapster.Tests/Mapster.Tests.csproj
index 76f179cf..63eb3b6e 100644
--- a/src/Mapster.Tests/Mapster.Tests.csproj
+++ b/src/Mapster.Tests/Mapster.Tests.csproj
@@ -9,15 +9,15 @@
true
-
-
-
-
+
+
+
-
+
+
diff --git a/src/Mapster.Tests/WhenMappingToInterface.cs b/src/Mapster.Tests/WhenMappingToInterface.cs
index d081641e..5e6f0358 100644
--- a/src/Mapster.Tests/WhenMappingToInterface.cs
+++ b/src/Mapster.Tests/WhenMappingToInterface.cs
@@ -206,9 +206,14 @@ public void MapToNotVisibleInterfaceThrows()
var ex = Should.Throw(() => dto.Adapt());
ex.InnerException.ShouldBeOfType();
- ex.InnerException.Message.ShouldContain("not accessible", "Correct InvalidOperationException must be thrown.");
+ // Not an expert in ShouldBe, so I had to change the code below
+ //ex.InnerException.Message.ShouldContain("", "Correct InvalidOperationException must be thrown.");
+ if (!ex.InnerException.Message.Contains("not accessible"))
+ {
+ throw new InvalidOperationException("Correct InvalidOperationException must be thrown.");
+ }
}
-
+
[TestMethod]
public void MapToInheritedInterfaceWithoutProperties()
{
diff --git a/src/Mapster.Tool/Mapster.Tool.csproj b/src/Mapster.Tool/Mapster.Tool.csproj
index 71e088e6..8e4c1b2f 100644
--- a/src/Mapster.Tool/Mapster.Tool.csproj
+++ b/src/Mapster.Tool/Mapster.Tool.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp3.1;net5.0;net6.0
+ net6.0
true
true
dotnet-mapster
@@ -20,11 +20,11 @@
-
-
+
+
diff --git a/src/Mapster.sln b/src/Mapster.sln
index 2fd8a0cd..f5df1d5e 100644
--- a/src/Mapster.sln
+++ b/src/Mapster.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29709.97
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A5580F9D-0F5F-4224-980F-7824536A627D}"
ProjectSection(SolutionItems) = preProject
@@ -55,6 +55,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mapster.SourceGenerator", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mapster.Core", "Mapster.Core\Mapster.Core.csproj", "{1A7D2FD4-DDEC-4E11-93FF-1310F34F67CF}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExpressionDebugger", "ExpressionDebugger\ExpressionDebugger.csproj", "{7358E975-3588-424F-8859-8AFFEF5B4A1E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExpressionTranslator", "ExpressionTranslator\ExpressionTranslator.csproj", "{411B0A68-AA3B-441E-BC8C-CCE1FBE88AFA}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemplateTest", "TemplateTest\TemplateTest.csproj", "{ED390145-FA22-46BA-86A6-9FA6AC869BA4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -137,6 +143,18 @@ Global
{1A7D2FD4-DDEC-4E11-93FF-1310F34F67CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A7D2FD4-DDEC-4E11-93FF-1310F34F67CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A7D2FD4-DDEC-4E11-93FF-1310F34F67CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7358E975-3588-424F-8859-8AFFEF5B4A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7358E975-3588-424F-8859-8AFFEF5B4A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7358E975-3588-424F-8859-8AFFEF5B4A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7358E975-3588-424F-8859-8AFFEF5B4A1E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {411B0A68-AA3B-441E-BC8C-CCE1FBE88AFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {411B0A68-AA3B-441E-BC8C-CCE1FBE88AFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {411B0A68-AA3B-441E-BC8C-CCE1FBE88AFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {411B0A68-AA3B-441E-BC8C-CCE1FBE88AFA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ED390145-FA22-46BA-86A6-9FA6AC869BA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ED390145-FA22-46BA-86A6-9FA6AC869BA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ED390145-FA22-46BA-86A6-9FA6AC869BA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ED390145-FA22-46BA-86A6-9FA6AC869BA4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -156,6 +174,7 @@ Global
{DE045991-6268-46EE-B5D3-79DE75820976} = {916FA044-B9E5-44F2-991A-85AA43C08255}
{D5DF0FB7-44A5-4326-9EC4-5B8F7FCCE00F} = {D33E5A90-ABCA-4B2D-8758-2873CC5AB847}
{3CB56440-5449-4DE5-A8D3-549C87C1B36A} = {EF7E343F-592E-4EAC-A0A4-92EB4B95CB89}
+ {ED390145-FA22-46BA-86A6-9FA6AC869BA4} = {D33E5A90-ABCA-4B2D-8758-2873CC5AB847}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {83B87DBA-277C-49F1-B597-E3B78C2C8275}
diff --git a/src/Mapster/Mapster.csproj b/src/Mapster/Mapster.csproj
index 20f83f32..d7588978 100644
--- a/src/Mapster/Mapster.csproj
+++ b/src/Mapster/Mapster.csproj
@@ -2,7 +2,9 @@
A fast, fun and stimulating object to object mapper. Kind of like AutoMapper, just simpler and way, way faster.
- netstandard2.0;netstandard1.3
+ Copyright (c) 2016 Chaowlert Chaisrichalermpol, Eric Swann
+ chaowlert;eric_swann
+ net6.0
Mapster
A fast, fun and stimulating object to object mapper. Kind of like AutoMapper, just simpler and way, way faster.
Mapster
diff --git a/src/Mapster/Utils/CoreExtensions.cs b/src/Mapster/Utils/CoreExtensions.cs
index 7e56ba5e..e5866402 100644
--- a/src/Mapster/Utils/CoreExtensions.cs
+++ b/src/Mapster/Utils/CoreExtensions.cs
@@ -25,9 +25,11 @@ public static void LockRemove(this List list, T item)
}
}
+#if !NET6_0_OR_GREATER
public static HashSet ToHashSet(this IEnumerable source)
{
return new HashSet(source);
}
+#endif
}
}
diff --git a/src/Mapster/Utils/CustomAttributeUtil.cs b/src/Mapster/Utils/CustomAttributeUtil.cs
index 4b487b5e..1cbaad1d 100644
--- a/src/Mapster/Utils/CustomAttributeUtil.cs
+++ b/src/Mapster/Utils/CustomAttributeUtil.cs
@@ -42,7 +42,7 @@ public static bool IsField(this CustomAttributeNamedArgument arg)
#endif
-#if NETSTANDARD1_3
+#if NETSTANDARD1_3 || NET6_0_OR_GREATER
public static IEnumerable GetCustomAttributesData(this ParameterInfo parameter)
{
return parameter.CustomAttributes;
diff --git a/src/Mapster/Utils/DynamicTypeGenerator.cs b/src/Mapster/Utils/DynamicTypeGenerator.cs
index 0d36d59c..7e901417 100644
--- a/src/Mapster/Utils/DynamicTypeGenerator.cs
+++ b/src/Mapster/Utils/DynamicTypeGenerator.cs
@@ -101,7 +101,7 @@ private static Type CreateTypeForInterface(Type interfaceType)
ctorIl.Emit(OpCodes.Ret);
}
-#if NETSTANDARD2_0
+#if NETSTANDARD2_0 || NET6_0_OR_GREATER
return builder.CreateTypeInfo()!;
#elif NETSTANDARD1_3
return builder.CreateTypeInfo().AsType();
diff --git a/src/Sample.AspNetCore/Controllers/SchoolController.cs b/src/Sample.AspNetCore/Controllers/SchoolController.cs
index 096f58f6..7bd8e216 100644
--- a/src/Sample.AspNetCore/Controllers/SchoolController.cs
+++ b/src/Sample.AspNetCore/Controllers/SchoolController.cs
@@ -6,9 +6,9 @@
using Mapster;
using Sample.AspNetCore.Models;
using MapsterMapper;
-using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
+using Microsoft.AspNetCore.OData.Query;
namespace Sample.AspNetCore.Controllers
{
diff --git a/src/Sample.AspNetCore/Sample.AspNetCore.csproj b/src/Sample.AspNetCore/Sample.AspNetCore.csproj
index f2f49b18..9866b4a4 100644
--- a/src/Sample.AspNetCore/Sample.AspNetCore.csproj
+++ b/src/Sample.AspNetCore/Sample.AspNetCore.csproj
@@ -6,10 +6,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Sample.AspNetCore/Startup.cs b/src/Sample.AspNetCore/Startup.cs
index 18d68e71..8b1ee9b8 100644
--- a/src/Sample.AspNetCore/Startup.cs
+++ b/src/Sample.AspNetCore/Startup.cs
@@ -5,12 +5,12 @@
using Sample.AspNetCore.Controllers;
using Sample.AspNetCore.Models;
using MapsterMapper;
-using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.AspNetCore.OData;
namespace Sample.AspNetCore
{
@@ -27,6 +27,7 @@ public Startup(IConfiguration configuration)
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(opts => opts.EnableEndpointRouting = false)
+ .AddOData(options => options.Select().Filter().OrderBy())
.AddNewtonsoftJson();
services.AddDbContext(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
@@ -34,7 +35,6 @@ public void ConfigureServices(IServiceCollection services)
services.AddScoped();
services.AddSingleton();
services.AddProblemDetails();
- services.AddOData();
}
private static TypeAdapterConfig GetConfiguredMappingConfig()
@@ -72,11 +72,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseProblemDetails();
app.UseRouting();
app.UseAuthorization();
- app.UseMvc(builder =>
- {
- builder.EnableDependencyInjection();
- builder.Select().Expand().Filter().OrderBy().MaxTop(1000).Count();
- });
+ app.UseMvc();
}
}
}
diff --git a/src/Sample.CodeGen/Controllers/SchoolController.cs b/src/Sample.CodeGen/Controllers/SchoolController.cs
index c94e2231..c9a588df 100644
--- a/src/Sample.CodeGen/Controllers/SchoolController.cs
+++ b/src/Sample.CodeGen/Controllers/SchoolController.cs
@@ -1,8 +1,8 @@
using System.Linq;
using System.Threading.Tasks;
using Hellang.Middleware.ProblemDetails;
-using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.OData.Query;
using Microsoft.EntityFrameworkCore;
using Sample.CodeGen.Domains;
using Sample.CodeGen.Mappers;
diff --git a/src/Sample.CodeGen/Properties/launchSettings.json b/src/Sample.CodeGen/Properties/launchSettings.json
index da6fc229..5aa2546c 100644
--- a/src/Sample.CodeGen/Properties/launchSettings.json
+++ b/src/Sample.CodeGen/Properties/launchSettings.json
@@ -11,6 +11,7 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
+ "launchUrl": "school/course",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@@ -18,6 +19,7 @@
"Sample.CodeGen": {
"commandName": "Project",
"launchBrowser": true,
+ "launchUrl": "school/course",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
diff --git a/src/Sample.CodeGen/Sample.CodeGen.csproj b/src/Sample.CodeGen/Sample.CodeGen.csproj
index f63cee31..03a79b04 100644
--- a/src/Sample.CodeGen/Sample.CodeGen.csproj
+++ b/src/Sample.CodeGen/Sample.CodeGen.csproj
@@ -6,12 +6,11 @@
-
-
-
-
-
-
+
+
+
+
+
@@ -27,6 +26,9 @@
+
+
+
PreserveNewest
diff --git a/src/Sample.CodeGen/Startup.cs b/src/Sample.CodeGen/Startup.cs
index f74f1008..8b0cad18 100644
--- a/src/Sample.CodeGen/Startup.cs
+++ b/src/Sample.CodeGen/Startup.cs
@@ -1,7 +1,7 @@
using Hellang.Middleware.ProblemDetails;
-using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.OData;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -23,11 +23,11 @@ public Startup(IConfiguration configuration)
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(opts => opts.EnableEndpointRouting = false)
+ .AddOData(options => options.Select().Filter().OrderBy())
.AddNewtonsoftJson();
services.AddDbContext(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddProblemDetails();
- services.AddOData();
services.Scan(selector => selector.FromCallingAssembly()
.AddClasses().AsMatchingInterface().WithSingletonLifetime());
}
@@ -38,11 +38,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseProblemDetails();
app.UseRouting();
app.UseAuthorization();
- app.UseMvc(builder =>
- {
- builder.EnableDependencyInjection();
- builder.Select().Expand().Filter().OrderBy().MaxTop(1000).Count();
- });
+ app.UseMvc();
}
}
}
diff --git a/src/TemplateTest/CreateMapExpressionTest.cs b/src/TemplateTest/CreateMapExpressionTest.cs
new file mode 100644
index 00000000..4929bb12
--- /dev/null
+++ b/src/TemplateTest/CreateMapExpressionTest.cs
@@ -0,0 +1,105 @@
+using ExpressionDebugger;
+using Mapster;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections.Generic;
+
+namespace TemplateTest
+{
+ [TestClass]
+ public class CreateMapExpressionTest
+ {
+ [TestMethod]
+ public void TestCreateMapExpression()
+ {
+ TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true;
+ var foo = default(Customer);
+ var def = new ExpressionDefinitions
+ {
+ IsStatic = true,
+ MethodName = "Map",
+ Namespace = "Benchmark",
+ TypeName = "CustomerMapper"
+ };
+ var code = foo.BuildAdapter()
+ .CreateMapExpression()
+ .ToScript(def);
+
+ Assert.IsNotNull(code);
+ }
+
+ [TestMethod]
+ public void TestCreateMapToTargetExpression()
+ {
+ TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true;
+ var foo = default(Customer);
+ var def = new ExpressionDefinitions
+ {
+ IsStatic = true,
+ MethodName = "Map",
+ Namespace = "Benchmark",
+ TypeName = "CustomerMapper"
+ };
+ var code = foo.BuildAdapter()
+ .CreateMapToTargetExpression()
+ .ToScript(def);
+
+ Assert.IsNotNull(code);
+ }
+
+ [TestMethod]
+ public void TestCreateProjectionExpression()
+ {
+ TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true;
+ var foo = default(Customer);
+ var def = new ExpressionDefinitions
+ {
+ IsStatic = true,
+ MethodName = "Map",
+ Namespace = "Benchmark",
+ TypeName = "CustomerMapper"
+ };
+ var code = foo.BuildAdapter()
+ .CreateProjectionExpression()
+ .ToScript(def);
+
+ Assert.IsNotNull(code);
+ }
+ }
+
+ public class Address
+ {
+ public int Id { get; set; }
+ public string Street { get; set; }
+ public string City { get; set; }
+ public string Country { get; set; }
+ }
+
+ public class AddressDTO
+ {
+ public int Id { get; set; }
+ public string City { get; set; }
+ public string Country { get; set; }
+ }
+
+ public class Customer
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public decimal? Credit { get; set; }
+ public Address Address { get; set; }
+ public Address HomeAddress { get; set; }
+ public Address[] Addresses { get; set; }
+ public ICollection WorkAddresses { get; set; }
+ }
+
+ public class CustomerDTO
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public AddressDTO Address { get; set; }
+ public AddressDTO HomeAddress { get; set; }
+ public AddressDTO[] Addresses { get; set; }
+ public List WorkAddresses { get; set; }
+ public string AddressCity { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/TemplateTest/FooTest.cs b/src/TemplateTest/FooTest.cs
new file mode 100644
index 00000000..942bf4f8
--- /dev/null
+++ b/src/TemplateTest/FooTest.cs
@@ -0,0 +1,59 @@
+using ExpressionDebugger;
+using Mapster;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+
+namespace TemplateTest
+{
+ [TestClass]
+ public class FooTest
+ {
+ [TestMethod]
+ public void TestCreateMapExpression()
+ {
+ TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true;
+ var foo = default(Foo);
+ var def = new ExpressionDefinitions
+ {
+ IsStatic = true,
+ MethodName = "Map",
+ Namespace = "Benchmark",
+ TypeName = "FooMapper"
+ };
+ var code = foo.BuildAdapter()
+ .CreateMapExpression()
+ .ToScript(def);
+ code = code.Replace("TypeAdapter.Map.Invoke", "Map");
+
+ Assert.IsNotNull(code);
+ }
+ }
+
+ public class Foo
+ {
+ public string Name { get; set; }
+
+ public int Int32 { get; set; }
+
+ public long Int64 { set; get; }
+
+ public int? NullInt { get; set; }
+
+ public float Floatn { get; set; }
+
+ public double Doublen { get; set; }
+
+ public DateTime DateTime { get; set; }
+
+ public Foo Foo1 { get; set; }
+
+ public IEnumerable Foos { get; set; }
+
+ public Foo[] FooArr { get; set; }
+
+ public int[] IntArr { get; set; }
+
+ public IEnumerable Ints { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/TemplateTest/TemplateTest.csproj b/src/TemplateTest/TemplateTest.csproj
new file mode 100644
index 00000000..34af174b
--- /dev/null
+++ b/src/TemplateTest/TemplateTest.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+