10 | {
11 | public class Option : ExpressionVisitor
12 | {
13 | protected override Expression VisitParameter(ParameterExpression p)//替换掉对象
14 | {
15 | if (p.Name == "name" && p.Type == typeof(string))
16 | return p;
17 | if (p.Type == typeof(P))
18 | return _parameterTuple.Source;
19 | return p;
20 | }
21 | protected override Expression VisitMethodCall(MethodCallExpression node)
22 | {
23 | //判断调用方法的实例是否为AutoCopy<>的派生类
24 | if (node.Object != null && IsAssignableToGenericType(node.Object.Type, typeof(AutoCopy<,>)))
25 | {
26 | //获取调用方法的实例
27 | var member = (MemberExpression)node.Object;
28 | var argument = Visit(node.Arguments[0]);
29 | var constant = (ConstantExpression)member.Expression;
30 | var anonymousClassInstance = constant.Value;
31 | var calledClassField = (FieldInfo)member.Member;
32 | var calledClass = calledClassField.GetValue(anonymousClassInstance);
33 | //调用实例的RegisterCore方法,获取Lambda表达式
34 | var autoCopyType = calledClass.GetType();
35 | object lambda = autoCopyType.InvokeMember("Decompiler", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, calledClass, new object[] { false });
36 | LambdaExpression lambdaExpression = (LambdaExpression)lambda;
37 | return Expression.Invoke(lambdaExpression, argument, _parameterTuple.ErrorMsg);
38 | }
39 | return base.VisitMethodCall(node);
40 | }
41 | private ParameterTuple _parameterTuple;
42 | public Option(ParameterTuple parameterTuple)
43 | {
44 | _parameterTuple = parameterTuple;
45 | }
46 | public Expression MapFrom(
47 | Expression> selector)
48 | {
49 | Expression body = selector;
50 | if (body is LambdaExpression)
51 | {
52 | body = ((LambdaExpression)body).Body;
53 | }
54 | var body2 = Visit(body);
55 | return body2;
56 | }
57 | public Expression MapFrom(Expression> selector)
58 | {
59 | Expression body = selector;
60 | if (body is LambdaExpression)
61 | {
62 | body = ((LambdaExpression)body).Body;
63 | }
64 | var body2 = Visit(body);
65 | return body2;
66 | }
67 | public Func ResolveUsing(Func resolver)
68 | {
69 | return resolver;
70 | }
71 | bool IsAssignableToGenericType(Type givenType, Type genericType)
72 | {
73 | var interfaceTypes = givenType.GetInterfaces();
74 |
75 | foreach (var it in interfaceTypes)
76 | {
77 | if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
78 | return true;
79 | }
80 |
81 | if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
82 | return true;
83 |
84 | Type baseType = givenType.BaseType;
85 | if (baseType == null) return false;
86 |
87 | return IsAssignableToGenericType(baseType, genericType);
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/DataRowTest/SimpleModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DataRowTest
4 | {
5 | public class SimpleModel
6 | {
7 | #region 变量定义
8 |
9 | private int _id = -1;
10 |
11 | private string _title = String.Empty;
12 |
13 | private string _gotourl = String.Empty;
14 |
15 | private DateTime _stime = DateTime.Now;
16 |
17 | private DateTime _etime = DateTime.Now;
18 |
19 | private string _runHour = String.Empty;
20 |
21 | private string _beizhu = String.Empty;
22 |
23 | private int _state = -1;
24 |
25 | private short _clickType = -1;
26 |
27 | private string _apkurl = String.Empty;
28 |
29 | private string _packageName = String.Empty;
30 |
31 | private string _mD5 = String.Empty;
32 |
33 | private short _silence = -1;
34 | #endregion
35 |
36 | #region 构造函数
37 |
38 | ///
39 | ///
40 | ///
41 | public SimpleModel()
42 | {
43 | }
44 | ///
45 | ///
46 | ///
47 | public SimpleModel
48 | (
49 | int id,
50 | string title,
51 | string gotourl,
52 | DateTime stime,
53 | DateTime etime,
54 | string runHour,
55 | string beizhu,
56 | int state,
57 | short clickType,
58 | string apkurl,
59 | string packageName,
60 | string mD5,
61 | short silence
62 | )
63 | {
64 | _id = id;
65 | _title = title;
66 | _gotourl = gotourl;
67 | _stime = stime;
68 | _etime = etime;
69 | _runHour = runHour;
70 | _beizhu = beizhu;
71 | _state = state;
72 | _clickType = clickType;
73 | _apkurl = apkurl;
74 | _packageName = packageName;
75 | _mD5 = mD5;
76 | _silence = silence;
77 |
78 | }
79 | #endregion
80 |
81 | #region 公共属性
82 |
83 |
84 | ///
85 | ///
86 | ///
87 | public int id
88 | {
89 | get { return _id; }
90 | set { _id = value; }
91 | }
92 |
93 | public string Title
94 | {
95 | get { return _title; }
96 | set { _title = value; }
97 | }
98 |
99 | public string Gotourl
100 | {
101 | get { return _gotourl; }
102 | set { _gotourl = value; }
103 | }
104 |
105 | public DateTime Stime
106 | {
107 | get { return _stime; }
108 | set { _stime = value; }
109 | }
110 |
111 | public DateTime Etime
112 | {
113 | get { return _etime; }
114 | set { _etime = value; }
115 | }
116 |
117 | public string RunHour
118 | {
119 | get { return _runHour; }
120 | set { _runHour = value; }
121 | }
122 |
123 | public string Beizhu
124 | {
125 | get { return _beizhu; }
126 | set { _beizhu = value; }
127 | }
128 |
129 | public int State
130 | {
131 | get { return _state; }
132 | set { _state = value; }
133 | }
134 |
135 | public short ClickType
136 | {
137 | get { return _clickType; }
138 | set { _clickType = value; }
139 | }
140 |
141 | public string Apkurl
142 | {
143 | get { return _apkurl; }
144 | set { _apkurl = value; }
145 | }
146 |
147 | public string PackageName
148 | {
149 | get { return _packageName; }
150 | set { _packageName = value; }
151 | }
152 |
153 | public string MD5
154 | {
155 | get { return _mD5; }
156 | set { _mD5 = value; }
157 | }
158 |
159 | public short Silence
160 | {
161 | get { return _silence; }
162 | set { _silence = value; }
163 | }
164 |
165 | #endregion
166 |
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/AutoCopyLib/AutoCopyLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C2685DAB-9618-4FDC-8E85-248E1069AC39}
8 | Library
9 | Properties
10 | AutoCopyLib
11 | AutoCopyLib
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | False
35 | .\DelegateDecompiler.dll
36 |
37 |
38 | False
39 | .\Mono.Reflection.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
89 |
--------------------------------------------------------------------------------
/Console.Test/Console.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {619CDDB5-2283-499C-BEFB-7B32C10FAEA7}
8 | Exe
9 | Properties
10 | Benchmark
11 | Benchmark
12 | v4.5
13 | 512
14 | publish\
15 | true
16 | Disk
17 | false
18 | Foreground
19 | 7
20 | Days
21 | false
22 | false
23 | true
24 | 0
25 | 1.0.0.%2a
26 | false
27 | false
28 | true
29 |
30 |
31 |
32 | AnyCPU
33 | true
34 | full
35 | false
36 | bin\Debug\
37 | DEBUG;TRACE
38 | prompt
39 | 4
40 | false
41 |
42 |
43 | AnyCPU
44 | pdbonly
45 | true
46 | bin\Release\
47 | TRACE
48 | prompt
49 | 4
50 | false
51 |
52 |
53 |
54 | ..\packages\AutoMapper.6.2.2\lib\net45\AutoMapper.dll
55 | True
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | False
80 | Microsoft .NET Framework 4.5 %28x86 和 x64%29
81 | true
82 |
83 |
84 | False
85 | .NET Framework 3.5 SP1
86 | false
87 |
88 |
89 |
90 |
91 | {c2685dab-9618-4fdc-8e85-248e1069ac39}
92 | AutoCopyLib
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
107 |
--------------------------------------------------------------------------------
/AutoCopyLib/Utilities/StaticReflection.cs:
--------------------------------------------------------------------------------
1 | // Original C# code written by
2 | // Unity - https://github.com/unitycontainer/unity
3 | // Copyright (C) 2015-2017 Microsoft
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product except in
6 | // compliance with the License. You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software distributed under the License is
11 | // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and limitations under the License.
13 | //
14 |
15 | using System;
16 | using System.Linq.Expressions;
17 | using System.Reflection;
18 |
19 | namespace AutoCopyLib.Utilities
20 | {
21 | public static class StaticReflection
22 | {
23 | public static MethodInfo GetMethodInfo(Expression expression)
24 | {
25 | return StaticReflection.GetMethodInfo((LambdaExpression)expression);
26 | }
27 | public static MethodInfo GetMethodInfo(Expression> expression)
28 | {
29 | return StaticReflection.GetMethodInfo((LambdaExpression)expression);
30 | }
31 | public static MethodInfo GetMethodInfo(Expression> expression)
32 | {
33 | return StaticReflection.GetMethodInfo((LambdaExpression)expression);
34 | }
35 | public static MethodInfo GetMethodInfo(Expression> expression)
36 | {
37 | return StaticReflection.GetMethodInfo((LambdaExpression)expression);
38 | }
39 |
40 | private static MethodInfo GetMethodInfo(LambdaExpression lambda)
41 | {
42 | StaticReflection.GuardProperExpressionForm(lambda.Body);
43 | return ((MethodCallExpression)lambda.Body).Method;
44 | }
45 |
46 | public static MethodInfo GetPropertyGetMethodInfo(Expression> expression)
47 | {
48 | MethodInfo getMethod = StaticReflection.GetPropertyInfo(expression).GetGetMethod(true);
49 | if (getMethod == (MethodInfo)null)
50 | {
51 | throw new InvalidOperationException("Invalid expression form passed");
52 | }
53 | return getMethod;
54 | }
55 |
56 | public static MethodInfo GetPropertySetMethodInfo(Expression> expression)
57 | {
58 | MethodInfo setMethod = StaticReflection.GetPropertyInfo(expression).GetSetMethod(true);
59 | if (setMethod == (MethodInfo)null)
60 | {
61 | throw new InvalidOperationException("Invalid expression form passed");
62 | }
63 | return setMethod;
64 | }
65 |
66 | private static PropertyInfo GetPropertyInfo(LambdaExpression lambda)
67 | {
68 | MemberExpression obj = lambda.Body as MemberExpression;
69 | if (obj == null)
70 | {
71 | throw new InvalidOperationException("Invalid expression form passed");
72 | }
73 | PropertyInfo obj2 = obj.Member as PropertyInfo;
74 | if (obj2 == (PropertyInfo)null)
75 | {
76 | throw new InvalidOperationException("Invalid expression form passed");
77 | }
78 | return obj2;
79 | }
80 |
81 | public static MemberInfo GetMemberInfo(Expression> expression)
82 | {
83 | Guard.ArgumentNotNull(expression, "expression");
84 | MemberExpression obj = expression.Body as MemberExpression;
85 | if (obj == null)
86 | {
87 | throw new InvalidOperationException("invalid expression form passed");
88 | }
89 | MemberInfo member = obj.Member;
90 | if (member == (MemberInfo)null)
91 | {
92 | throw new InvalidOperationException("Invalid expression form passed");
93 | }
94 | return member;
95 | }
96 |
97 | public static ConstructorInfo GetConstructorInfo(Expression> expression)
98 | {
99 | Guard.ArgumentNotNull(expression, "expression");
100 | NewExpression obj = expression.Body as NewExpression;
101 | if (obj == null)
102 | {
103 | throw new InvalidOperationException("Invalid expression form passed");
104 | }
105 | return obj.Constructor;
106 | }
107 |
108 | private static void GuardProperExpressionForm(Expression expression)
109 | {
110 | if (expression.NodeType == ExpressionType.Call)
111 | {
112 | return;
113 | }
114 | throw new InvalidOperationException("Invalid expression form passed");
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/AutoCopyLib/Visitors/NullsafeQueryRewriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq.Expressions;
4 | using System.Reflection;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace AutoCopyLib
8 | {
9 | public partial class AutoCopy
10 | {
11 | #region copied from NeinLinq (MIT License): https://github.com/axelheer/nein-linq/blob/master/src/NeinLinq/NullsafeQueryRewriter.cs
12 | internal class NullsafeQueryRewriter : ExpressionVisitor
13 | {
14 | private static readonly LockingConcurrentDictionary cache = new LockingConcurrentDictionary(new Func(NullsafeQueryRewriter.Fallback));
15 | protected override Expression VisitMember(MemberExpression node)
16 | {
17 | if (node == null)
18 | throw new ArgumentException(nameof(node));
19 | var target = Visit(node.Expression);
20 | if(!IsSafe(target))
21 | {
22 | return BeSafe(target, node, node.Update);
23 | }
24 | return node.Update(target);
25 | }
26 | protected override Expression VisitMethodCall(MethodCallExpression node)
27 | {
28 | if (node == null)
29 | throw new ArgumentNullException(nameof(node));
30 |
31 | var target = Visit(node.Object);
32 |
33 | if (!IsSafe(target))
34 | {
35 | // insert null-check before invoking instance method
36 | return BeSafe(target, node, fallback => node.Update(fallback, node.Arguments));
37 | }
38 |
39 | var arguments = Visit(node.Arguments);
40 |
41 | if (IsExtensionMethod(node.Method) && !IsSafe(arguments[0]))
42 | {
43 | // insert null-check before invoking extension method
44 | return BeSafe(arguments[0], node.Update(null, arguments), fallback =>
45 | {
46 | var args = new Expression[arguments.Count];
47 | arguments.CopyTo(args, 0);
48 | args[0] = fallback;
49 |
50 | return node.Update(null, args);
51 | });
52 | }
53 |
54 | return node.Update(target, arguments);
55 | }
56 | public Expression visit(Expression node)
57 | {
58 | return this.Visit(node);
59 | }
60 | static bool IsSafe(Expression expression)
61 | {
62 | // in method call results and constant values we trust to avoid too much conditions...
63 | return expression == null
64 | || expression.NodeType == ExpressionType.Call
65 | || expression.NodeType == ExpressionType.Constant
66 | || !IsNullableOrReferenceType(expression.Type);
67 | }
68 | static bool IsNullableOrReferenceType(Type type)
69 | {
70 | return !type.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(type) != null;
71 | }
72 | static Expression BeSafe(Expression target, Expression expression, Func update)
73 | {
74 | var fallback = cache.GetOrAdd(target.Type);
75 |
76 | if (fallback != null)
77 | {
78 | // coalesce instead, a bit intrusive but fast...
79 | return update(Expression.Coalesce(target, fallback));
80 | }
81 |
82 | // target can be null, which is why we are actually here...
83 | var targetFallback = Expression.Constant(null, target.Type);
84 |
85 | // expression can be default or null, which is basically the same...
86 | var expressionFallback = !IsNullableOrReferenceType(expression.Type)
87 | ? (Expression)Expression.Default(expression.Type) : Expression.Constant(null, expression.Type);
88 |
89 | return Expression.Condition(Expression.Equal(target, targetFallback), expressionFallback, expression);
90 | }
91 | static Expression Fallback(Type type)
92 | {
93 | // default values for generic collections
94 | if (type.IsConstructedGenericType && type.GenericTypeArguments.Length == 1)
95 | {
96 | return CollectionFallback(typeof(List<>), type)
97 | ?? CollectionFallback(typeof(HashSet<>), type);
98 | }
99 |
100 | // default value for arrays
101 | if (type.IsArray)
102 | {
103 | return Expression.NewArrayInit(type.GetElementType());
104 | }
105 |
106 | return null;
107 | }
108 |
109 | static Expression CollectionFallback(Type definition, Type type)
110 | {
111 | var collection = definition.MakeGenericType(type.GenericTypeArguments);
112 |
113 | // try if an instance of this collection would suffice
114 | if (type.GetTypeInfo().IsAssignableFrom(collection.GetTypeInfo()))
115 | {
116 | return Expression.Convert(Expression.New(collection), type);
117 | }
118 |
119 | return null;
120 | }
121 |
122 | static bool IsExtensionMethod(MethodInfo element)
123 | {
124 | return element.IsDefined(typeof(ExtensionAttribute), false);
125 | }
126 | }
127 | #endregion
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/Console.Test/Clock.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading;
6 |
7 | //copied from https://stackoverflow.com/questions/969290/exact-time-measurement-for-performance-testing
8 | namespace Benchmark
9 | {
10 | public static class Extensions
11 | {
12 | public static double NormalizedMean(this ICollection values)
13 | {
14 | if (values.Count == 0)
15 | return double.NaN;
16 |
17 | var deviations = values.Deviations().ToArray();
18 | var meanDeviation = deviations.Sum(t => Math.Abs(t.Item2)) / values.Count;
19 | return deviations.Where(t => t.Item2 > 0 || Math.Abs(t.Item2) <= meanDeviation).Average(t => t.Item1);
20 | }
21 |
22 | public static IEnumerable> Deviations(this ICollection values)
23 | {
24 | if (values.Count == 0)
25 | yield break;
26 |
27 | var avg = values.Average();
28 | foreach (var d in values)
29 | yield return Tuple.Create(d, avg - d);
30 | }
31 | }
32 | public class Clock
33 | {
34 | interface IStopwatch
35 | {
36 | bool IsRunning { get; }
37 | TimeSpan Elapsed { get; }
38 |
39 | void Start();
40 | void Stop();
41 | void Reset();
42 | }
43 |
44 |
45 |
46 | class TimeWatch : IStopwatch
47 | {
48 | Stopwatch stopwatch = new Stopwatch();
49 |
50 | public TimeSpan Elapsed
51 | {
52 | get { return stopwatch.Elapsed; }
53 | }
54 |
55 | public bool IsRunning
56 | {
57 | get { return stopwatch.IsRunning; }
58 | }
59 |
60 |
61 |
62 | public TimeWatch()
63 | {
64 | if (!Stopwatch.IsHighResolution)
65 | throw new NotSupportedException("Your hardware doesn't support high resolution counter");
66 |
67 | //prevent the JIT Compiler from optimizing Fkt calls away
68 | long seed = Environment.TickCount;
69 |
70 | //use the second Core/Processor for the test
71 | Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
72 |
73 | //prevent "Normal" Processes from interrupting Threads
74 | Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
75 |
76 | //prevent "Normal" Threads from interrupting this thread
77 | Thread.CurrentThread.Priority = ThreadPriority.Highest;
78 | }
79 |
80 |
81 |
82 | public void Start()
83 | {
84 | stopwatch.Start();
85 | }
86 |
87 | public void Stop()
88 | {
89 | stopwatch.Stop();
90 | }
91 |
92 | public void Reset()
93 | {
94 | stopwatch.Reset();
95 | }
96 | }
97 |
98 |
99 |
100 | class CpuWatch : IStopwatch
101 | {
102 | TimeSpan startTime;
103 | TimeSpan endTime;
104 | bool isRunning;
105 |
106 |
107 |
108 | public TimeSpan Elapsed
109 | {
110 | get
111 | {
112 | if (IsRunning)
113 | throw new NotImplementedException("Getting elapsed span while watch is running is not implemented");
114 |
115 | return endTime - startTime;
116 | }
117 | }
118 |
119 | public bool IsRunning
120 | {
121 | get { return isRunning; }
122 | }
123 |
124 |
125 |
126 | public void Start()
127 | {
128 | startTime = Process.GetCurrentProcess().TotalProcessorTime;
129 | isRunning = true;
130 | }
131 |
132 | public void Stop()
133 | {
134 | endTime = Process.GetCurrentProcess().TotalProcessorTime;
135 | isRunning = false;
136 | }
137 |
138 | public void Reset()
139 | {
140 | startTime = TimeSpan.Zero;
141 | endTime = TimeSpan.Zero;
142 | }
143 | }
144 |
145 |
146 |
147 | public static void BenchmarkTime(string name, Action action, int iterations = 10000)
148 | {
149 | Benchmark(name, action, iterations);
150 | }
151 |
152 | static void Benchmark(string name, Action action, int iterations) where T : IStopwatch, new()
153 | {
154 | //clean Garbage
155 | GC.Collect();
156 |
157 | //wait for the finalizer queue to empty
158 | GC.WaitForPendingFinalizers();
159 |
160 | //clean Garbage
161 | GC.Collect();
162 |
163 | //warm up
164 | action();
165 |
166 | var stopwatch = new T();
167 | var timings = new double[5];
168 | for (int i = 0; i < timings.Length; i++)
169 | {
170 | stopwatch.Reset();
171 | stopwatch.Start();
172 | for (int j = 0; j < iterations; j++)
173 | action();
174 | stopwatch.Stop();
175 | timings[i] = stopwatch.Elapsed.TotalMilliseconds;
176 | }
177 | System.Console.WriteLine($"{name} executed normalized mean : " + timings.NormalizedMean().ToString());
178 | }
179 |
180 | public static void BenchmarkCpu(string name, Action action, int iterations = 10000)
181 | {
182 | Benchmark(name, action, iterations);
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/AutoCopyLib/TypeConverter.cs:
--------------------------------------------------------------------------------
1 | using AutoCopyLib.Utilities;
2 | using System;
3 | using System.Collections.Concurrent;
4 | using System.Collections.Generic;
5 | using System.Linq.Expressions;
6 | using System.Reflection;
7 |
8 | namespace AutoCopyLib
9 | {
10 | internal class TypeConverter
11 | {
12 | private static MethodInfo ChangeTypeMethod = null;
13 | private static ConcurrentDictionary _tryParseDic = new ConcurrentDictionary();
14 | private static ConcurrentDictionary _toStringDic = new ConcurrentDictionary();
15 | static TypeConverter()
16 | {
17 | ChangeTypeMethod = typeof(Convert).GetMethod("ChangeType", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(object), typeof(TypeCode) }, new ParameterModifier[0]);
18 | }
19 | public static bool TryConvert(Expression parameter, Type sourceType, Type destType, out Action, ParameterExpression, PropertyInfo, Func> act, out ParameterExpression variable)
20 | {
21 | Expression expression = null;
22 | variable = null;
23 | act = null;
24 | var typeCode = Type.GetTypeCode(sourceType);
25 | if (typeCode == TypeCode.Empty || typeCode == TypeCode.DBNull)
26 | return false;
27 | MethodInfo method = null;
28 | //判断是否可以显式转换
29 | if (destType.GetMethod("op_Explicit",new Type[] {sourceType })!=null)
30 | {
31 | expression = Expression.Convert(parameter, destType);
32 |
33 | }
34 | //判断是否可以隐式转换
35 | else if(destType.GetMethod("op_Implicit", new Type[] { sourceType }) != null)
36 | {
37 | expression = parameter;
38 | }
39 | //判断是否存在继承关系
40 | //Base base=Derive
41 | else if(destType.IsAssignableFrom(sourceType))
42 | {
43 | expression = parameter;
44 | }
45 | //判断是否存在Convert.ToXX方法
46 | else if (typeCode != TypeCode.String && typeCode != TypeCode.Object && Type.GetTypeCode(destType)!=TypeCode.Object)
47 | {
48 | method = typeof(Convert).GetMethod("To" + destType.Name, BindingFlags.Static | BindingFlags.Public, null, new Type[] { sourceType }, new ParameterModifier[0]);
49 | if (method != null)
50 | {
51 | expression = Expression.Call(null, method, parameter);
52 | }
53 | }
54 | if (expression!=null)
55 | {
56 | act = (list, p1, srcPropertyInfo, func) =>
57 | {
58 | list.Add(Expression.Assign(Expression.MakeMemberAccess(p1, srcPropertyInfo), func == null ? expression : func(expression)));
59 | };
60 | return true;
61 | }
62 | bool skipChangeType = false;
63 | // 目标类型是否存在TryParse方法————————否——————————ChangeType
64 | // | |
65 | // |是 |
66 | // | 否 否 |
67 | // 源类型是否为string———————————是否存在ToString方法—————
68 | // | |
69 | // |是 |是
70 | // |——————————————————————
71 | // |
72 | // |
73 | // 调用目标类型上的TryParse方法
74 | if ((method = _tryParseDic.GetOrAdd(destType, t => t.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string), t.MakeByRefType() }, new ParameterModifier[0]))) != null)
75 | {
76 | skipChangeType = true;
77 | MethodInfo toStringMethod = null;
78 | //首先判断sourceType是不是string
79 | var r = typeCode != TypeCode.String;
80 | if (r)
81 | {
82 | //如果类型不是string,就需要看该类是否定义了自己的ToString方法
83 | //BindingFlags.DeclaredOnly 标识只获取该类定义的方法,屏蔽继承的方法
84 | if ((toStringMethod = _toStringDic.GetOrAdd(sourceType, t => t.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, Type.EmptyTypes, new ParameterModifier[0]))) == null)
85 | {
86 | skipChangeType = false;
87 | }
88 | }
89 | if (skipChangeType)
90 | {
91 | Expression temp = parameter;
92 | //如果sourceType不是string
93 | if (r)
94 | {
95 | temp = Expression.Call(parameter, toStringMethod);
96 | }
97 | ParameterExpression p = VariableGenerator.Generate(destType);
98 | expression = Expression.Call(null, method, temp, p);
99 | act = (list, p1, srcPropertyInfo, func) =>
100 | {
101 | expression = Expression.IfThen(expression, Expression.Assign(Expression.MakeMemberAccess(p1, srcPropertyInfo), p));
102 | list.Add(expression);
103 | };
104 | variable = p;
105 | }
106 | }
107 | if (!skipChangeType)
108 | {
109 | expression = Expression.Convert(Expression.Call(null, ChangeTypeMethod, Expression.Convert(parameter, typeof(object)), Expression.Constant(Type.GetTypeCode(destType), typeof(TypeCode))), destType);
110 | act = (list, p1, srcPropertyInfo, func) =>
111 | {
112 | list.Add(Expression.Assign(Expression.MakeMemberAccess(p1, srcPropertyInfo), func == null ? expression : func(expression)));
113 | };
114 | }
115 | return true;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | ## AutoCopy
2 |
3 | AutoCopy 一个可以缩短开发时间的工具类,帮助程序员从某些繁重的人肉编码中解脱出来。灵感来自于**[AutoMapper](https://github.com/AutoMapper/AutoMapper "AutoMapper")**,初次使用AutoMapper时被它实现的功能深深吸引,但是在逐渐学习中发现AutoMapper速度不能令人满意,并且实现有些复杂,小白不容易看懂原理,所以萌生了自己写一个更简单、更高效类库的想法。在这样一个契机之下,AutoCopy应运而生(:clap::smirk:)。AutoCopy的一些方法模仿了AutoMapper的命名和使用方式,降低使用上的难度。
4 |
5 | ## 文档
6 |
7 | [英文版](README.md)
8 |
9 | ## 依赖
10 |
11 | * **[Mono.Reflection.dll](https://github.com/jbevain/mono.reflection "Mono.Reflection")**
12 | * **[DelegateDecompiler.dll](https://github.com/hazzik/DelegateDecompiler "DelegateDecompiler")**
13 |
14 | ## 特性
15 |
16 | 1. 执行速度快
17 | 2. 基于抽象类**TargetExpressionProviderBase**可以实现任意扩展
18 | 3. 支持自动/手工的类型转换
19 | 4. 支持多AutoCopy实例嵌套
20 |
21 | ## 基准测试
22 |
23 |
24 | 执行次数:100,000
25 |
26 | | 操作 | 平均时间(毫秒)
27 | ---|---
28 | 手动映射 | 4.267375
29 | AutoCopy | 4.18163333333333
30 | AutoMapper | 42.4985
31 |
32 | 执行次数:1,000,000
33 |
34 | | 操作 | 平均时间(毫秒)
35 | ---|---
36 | 手动映射 | 30.884225
37 | AutoCopy | 38.647675
38 | AutoMapper | 322.8877
39 |
40 | 执行次数:10,000,000
41 |
42 | | 操作 | 平均时间(毫秒)
43 | ---|---
44 | 手动映射 | 440.14825
45 | AutoCopy | 459.17575
46 | AutoMapper | 3895.974725
47 |
48 | Benchmark code see [here](/Console.Test/Program.cs)
49 |
50 |
51 | ## 原理说明
52 |
53 | 在调用**Register**方法时基于[Reflection](https://msdn.microsoft.com/en-us/library/system.reflection(v=vs.110).aspx "Reflection")分析源类和目标类的所有属性,并生成[Expression](https://msdn.microsoft.com/en-us/library/system.linq.expressions.expression(v=vs.110).aspx "Expression")列表,之后使用[Expression.Lambda](https://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.lambda(v=vs.110).aspx "Expression.Lambda")方法把Expression列表以及相应参数包装成[LambdaExpression](https://msdn.microsoft.com/en-us/library/system.linq.expressions.lambdaexpression(v=vs.110).aspx "LambdaExpression"),通过调用Compile方法编译为[Func Delegate](https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx "Func Delegate")。
54 |
55 | ## 示例
56 |
57 | ### 示例1 相同类型对象拷贝
58 |
59 | ```csharp
60 |
61 | public class Address
62 | {
63 | public string ZipCode { get; set; }
64 | }
65 |
66 | var autoCopy = AutoCopy.CreateMap();
67 |
68 | autoCopy.Register();
69 |
70 | Address a=new Address { ZipCode="1234567890"; };
71 |
72 | Address b=autoCopy.Map(a);
73 |
74 | ```
75 |
76 | ### 示例2 不同类型对象拷贝
77 |
78 | ```csharp
79 |
80 | public class Address
81 | {
82 | public string ZipCode { get; set; }
83 | }
84 |
85 | public class Telephone
86 | {
87 | public string Number { get; set; }
88 | }
89 |
90 | public class Customer
91 | {
92 | public Address Address { get; set; }
93 | public Telephone Phone { get; set; }
94 | public string Memo { get; set; }
95 | }
96 |
97 | public class CustomerInfo
98 | {
99 | public string zipCode { get; set; }
100 | public string PhoneNumber { get; set; }
101 | public string Memo { get; set; }
102 | }
103 |
104 | var autoCopy = AutoCopy.CreateMap();
105 |
106 | autoCopy
107 | .ForMember(p => p.zipCode, opt => opt.MapFrom(p => p.Address.ZipCode))
108 | .ForMember(p => p.PhoneNumber, opt => opt.MapFrom(p => p.Phone.Number));
109 |
110 | autoCopy.Register();
111 |
112 | Customer customer = new Customer();
113 |
114 | customer.Address = new Address { ZipCode = "1234567890" };
115 |
116 | customer.Phone = new Telephone { Number = "17791704580" };
117 |
118 | customer.Memo = "Test";
119 |
120 | CustomerInfo info = autoCopy.Map(customer);
121 |
122 | ```
123 |
124 | ### 示例3 多AutoCopy示例嵌套
125 |
126 | ```csharp
127 |
128 | public class Data
129 | {
130 | public int width { get; set; }
131 | public int height { get; set; }
132 | public string ua { get; set; }
133 | public string ip { get; set; }
134 | public string imei { get; set; }
135 | public string android_id { get; set; }
136 | public string make { get; set; }
137 | public string model { get; set; }
138 | public string os { get; set; }
139 | public string osv { get; set; }
140 | public int connectionType { get; set; }
141 | public int deviceType { get; set; }
142 | public string mac { get; set; }
143 | public int screenWidth { get; set; }
144 | public int screenHeight { get; set; }
145 | public string appName { get; set; }
146 | public int ppi { get; set; }
147 | public string dpidsha1 { get; set; }
148 | public string plmn { get; set; }
149 | public string orientation { get; set; }
150 | public int pos { get; set; }
151 | public bool instl { get; set; }
152 | public string ver { get; set; }
153 | public string bundle { get; set; }
154 | public Ext ext { get; set; }
155 | }
156 | public class Ext
157 | {
158 | public int ID { get; set; }
159 | }
160 |
161 | string surl = "id=10010&width=10&height=10&ua=ua&ip=127.0.0.1&imei=00000000000000&android_id=A00000000000000&make=1111111111&model=XXX&os=android&osv=4.0.1&connectionType=1&deviceType=1&mac=0.0.0.0.0.0.0&screenWidth=100&screenHeight=100&appName=test&ppi=600&dpidsha1=dpidsha1&plmn=1&orientation=1&pos=1&instl=true&ver=1.0.0&bundle=bundle";
162 |
163 | HttpQueryCollection collection = new HttpQueryCollection(surl, false);
164 |
165 | var ac = AutoCopy.CreateMap();
166 |
167 | ac.Provider= new HttpRequestParamsExpressionProvider(typeof(NameValueCollection));
168 |
169 | var autoCopy = AutoCopy.CreateMap();
170 |
171 | autoCopy.ForMember(p => p.ext, opt => opt.MapFrom(p=>ac.Map(p)));
172 |
173 | autoCopy.Provider = new HttpRequestParamsExpressionProvider(typeof(NameValueCollection));
174 |
175 | autoCopy.Register();
176 |
177 | Data data=autoCopy.Map(collection);
178 |
179 | ```
180 | ## 类型转换
181 | ### 自动转换
182 | 内部类[TypeConverter](/AutoCopyLib/TypeConverter.cs)的TryConvert方法通过以下顺序进行类型的自动转换:
183 |
184 | 1. 是否存在显式转换操作符
185 | 2. 是否存在隐式转换操作符
186 | 3. 是否存在继承关系
187 | 4. 是否存在Convert.ToXXX方法
188 | 5. 是否可以调用目标类型上的TryParse方法
189 | 6. 调用[Convert.ChangeType](https://msdn.microsoft.com/en-us/library/system.convert.changetype(v=vs.110).aspx "Convert.ChangeType")方法
190 | ### 手动转换
191 |
192 | 通过调用**AutoCopy**类实例的**ForTypeConvert**方法来注册类型转换。
193 |
194 | ## 抽象类[TargetExpressionProviderBase](/AutoCopyLib/TargetExpressionProviderBase.cs)的TryGetExpression方法参数说明
195 |
196 | 假定AutoCopy中T1为源类型,T2为目标类型
197 |
198 | | | 属性名 | 备注
199 | ---|---|---
200 | 1 | name | 目标属性名称
201 | 2 | parameter | 源类型的参数表达式
202 | 3 | destType | 目标类型
203 | 4 | exp | 通过TryGetExpression方法最后生成的表达式
204 | 5 | variable | 临时变量
205 | 6 | test | 测试表达式
206 | 7 | ifTrue | 是否需要测试;如果该值为true,则只有test执行返回true时才会继续执行exp
207 |
208 | ## 修改日志
209 | 2017-12-05 增加DataRow映射到实体类的示例程序
210 | 2017-12-13 调整了AutoCopy<,>类的参数顺序并且修改了Option.ResolveUsing方法参数类型错误的bug
211 | 2017-12-26 增加CopyMapAttribute特性来支持目标类型属性的别名映射
212 | 2017-12-27 增加CopyRequiredAttribute特性来支持检测目标类型属性所需要映射的值是否为空 **[需要进一步测试]**
213 | 2017-12-28 当Option.MapFrom函数中调用其他AutoCopy实例时从Decompiler函数中获取新的LambdaExpression
214 | 2018-01-12 重载Option.MapForm函数,添加一个字符串参数,指示目标的属性名称或映射名称
215 | 2018-02-09 修复bug:当将CopyRequired特性应用于需要AutoCopy实例嵌套映射的属性时,调用ConditionFalseRewriter类的Visit函数将导致错误
216 | ## 注意事项
217 |
218 | 由于AutoCopy在运行时通过主动调用**Register**方法使用反射分析类的属性,所以如果方法进行了混淆可能会出现Bug。
219 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## AutoCopy
2 |
3 | AutoCopy is a tool that reduces development time and helps programmers get out of some heavy human coding, which is inspired by **[AutoMapper](https://github.com/AutoMapper/AutoMapper "AutoMapper")**.
4 |
5 | ## Document
6 |
7 | [Chinese](README_CN.md)
8 |
9 | ## Dependencies
10 |
11 | * **[Mono.Reflection.dll](https://github.com/jbevain/mono.reflection "Mono.Reflection")**
12 | * **[DelegateDecompiler.dll](https://github.com/hazzik/DelegateDecompiler "DelegateDecompiler")**
13 |
14 | ## Attribute
15 |
16 | 1. Fast execution
17 | 2. Based on the abstract class **TargetExpressionProviderBase** can be any extension
18 | 3. Support automatic / manual type conversion
19 | 4. Support for multiple instances of AutoCopy nesting
20 |
21 | ## Benchmark
22 |
23 | iterations:100,000
24 |
25 | | Action | mean time(ms)
26 | ---|---
27 | hand map | 4.267375
28 | AutoCopy | 4.18163333333333
29 | AutoMapper | 42.4985
30 |
31 | iterations:1,000,000
32 |
33 | | Action | mean time(ms)
34 | ---|---
35 | hand map | 30.884225
36 | AutoCopy | 38.647675
37 | AutoMapper | 322.8877
38 |
39 | iterations:10,000,000
40 |
41 | | Action | mean time(ms)
42 | ---|---
43 | hand map | 440.14825
44 | AutoCopy | 459.17575
45 | AutoMapper | 3895.974725
46 |
47 | Benchmark code see [here](/Console.Test/Program.cs)
48 |
49 | ## Example
50 |
51 | ### 1 Same type of object copyed
52 |
53 | ```csharp
54 |
55 | public class Address
56 | {
57 | public string ZipCode { get; set; }
58 | }
59 |
60 | var autoCopy = AutoCopy.CreateMap();
61 |
62 | autoCopy.Register();
63 |
64 | Address a=new Address { ZipCode="1234567890"; };
65 |
66 | Address b=autoCopy.Map(a);
67 |
68 | ```
69 |
70 | ### 2 Different type of object copyed
71 |
72 | ```csharp
73 |
74 | public class Address
75 | {
76 | public string ZipCode { get; set; }
77 | }
78 |
79 | public class Telephone
80 | {
81 | public string Number { get; set; }
82 | }
83 |
84 | public class Customer
85 | {
86 | public Address Address { get; set; }
87 | public Telephone Phone { get; set; }
88 | public string Memo { get; set; }
89 | }
90 |
91 | public class CustomerInfo
92 | {
93 | public string zipCode { get; set; }
94 | public string PhoneNumber { get; set; }
95 | public string Memo { get; set; }
96 | }
97 |
98 | var autoCopy = AutoCopy.CreateMap();
99 |
100 | autoCopy
101 | .ForMember(p => p.zipCode, opt => opt.MapFrom(p => p.Address.ZipCode))
102 | .ForMember(p => p.PhoneNumber, opt => opt.MapFrom(p => p.Phone.Number));
103 |
104 | autoCopy.Register();
105 |
106 | Customer customer = new Customer();
107 |
108 | customer.Address = new Address { ZipCode = "1234567890" };
109 |
110 | customer.Phone = new Telephone { Number = "17791704580" };
111 |
112 | customer.Memo = "Test";
113 |
114 | CustomerInfo info = autoCopy.Map(customer);
115 |
116 | ```
117 |
118 | ### 3 Multiple AutoCopy instances nested
119 |
120 | ```csharp
121 |
122 | public class Data
123 | {
124 | public int width { get; set; }
125 | public int height { get; set; }
126 | public string ua { get; set; }
127 | public string ip { get; set; }
128 | public string imei { get; set; }
129 | public string android_id { get; set; }
130 | public string make { get; set; }
131 | public string model { get; set; }
132 | public string os { get; set; }
133 | public string osv { get; set; }
134 | public int connectionType { get; set; }
135 | public int deviceType { get; set; }
136 | public string mac { get; set; }
137 | public int screenWidth { get; set; }
138 | public int screenHeight { get; set; }
139 | public string appName { get; set; }
140 | public int ppi { get; set; }
141 | public string dpidsha1 { get; set; }
142 | public string plmn { get; set; }
143 | public string orientation { get; set; }
144 | public int pos { get; set; }
145 | public bool instl { get; set; }
146 | public string ver { get; set; }
147 | public string bundle { get; set; }
148 | public Ext ext { get; set; }
149 | }
150 | public class Ext
151 | {
152 | public int ID { get; set; }
153 | }
154 |
155 | string surl = "id=10010&width=10&height=10&ua=ua&ip=127.0.0.1&imei=00000000000000&android_id=A00000000000000&make=1111111111&model=XXX&os=android&osv=4.0.1&connectionType=1&deviceType=1&mac=0.0.0.0.0.0.0&screenWidth=100&screenHeight=100&appName=test&ppi=600&dpidsha1=dpidsha1&plmn=1&orientation=1&pos=1&instl=true&ver=1.0.0&bundle=bundle";
156 |
157 | HttpQueryCollection collection = new HttpQueryCollection(surl, false);
158 |
159 | var ac = AutoCopy.CreateMap();
160 |
161 | ac.Provider= new HttpRequestParamsExpressionProvider(typeof(NameValueCollection));
162 |
163 | var autoCopy = AutoCopy.CreateMap();
164 |
165 | autoCopy.ForMember(p => p.ext, opt => opt.MapFrom(p=>ac.Map(p)));
166 |
167 | autoCopy.Provider = new HttpRequestParamsExpressionProvider(typeof(NameValueCollection));
168 |
169 | autoCopy.Register();
170 |
171 | Data data=autoCopy.Map(collection);
172 |
173 | ```
174 | ## Type Convert
175 | ### Automatic conversion
176 | The TryConvert method of the internal class [TypeConverter](/AutoCopyLib/TypeConverter.cs) performs automatic conversion of the type in the following order:
177 |
178 | 1. Whether there is a explicit operator
179 | 2. Whether there is a implicit operator
180 | 3. Whether it is a subclass
181 | 4. Whether there is the Convert.ToXXX method
182 | 5. Whether there is the TryParse method on the target type
183 | 6. Call [Convert.ChangeType](https://msdn.microsoft.com/en-us/library/system.convert.changetype(v=vs.110).aspx "Convert.ChangeType") method
184 | ### Manual conversion
185 |
186 | Type conversions are registered by calling the **ForTypeConvert** method of the **AutoCopy** instance.
187 |
188 | ## Explanation of Parameter in [TryGetExpression](/AutoCopyLib/TargetExpressionProviderBase.cs) method
189 |
190 | With AutoCopy, assume T1 is the source type and T2 is the destination type
191 |
192 | | | Parameter Name | Description
193 | ---|---|---
194 | 1 | name | destination property name
195 | 2 | parameter | Expression of source parameter Expression
196 | 3 | destType | destination type
197 | 4 | exp | the final Expression
198 | 5 | variable | variables
199 | 6 | test | test Expression
200 | 7 | ifTrue | Whether need to test or not; If the value is true, then only the test Expression executed return true can exp Expression will be called
201 |
202 | ## ChangeLog
203 | 2017-12-05 Add a demo which show the DataRow class convert to entity class
204 | 2017-12-12 Adjust the order of parameters in AutoCopy<,> and fixed the parameter type bug in Option.ResolveUsing
205 | 2017-12-26 Add the CopyMapAttribute attribute to support alias mapping of destination type property
206 | 2017-12-27 Add the CopyRequiredAttribute attribute to support the detection of the destination type property map value is required to be empty **[Need further testing]**
207 | 2017-12-28 Get a new LambdaExpression from the Decompiler function when another AutoCopy instance is called in the Option.MapFrom function
208 | 2018-01-12 Overload the Option.MapForm function, add a string parameter indicating the target's property name or mapping name
209 | 2018-02-09 fixed bug: When the CopyRequired attribute is applied to a property that requires nested mapping of an AutoCopy instance, called the Visit function of ConditionFalseRewriter class would cause error
210 | ## Warning
211 |
212 | Since AutoCopy uses reflection at runtime to analysis the properties of classes by calling **Register** methods automatically, bugs may occur if the source code is obfuscated.
213 |
--------------------------------------------------------------------------------
/AutoCopyLib/ReflectExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Reflection.Emit;
6 | using System.Text;
7 |
8 | namespace AutoCopyLib
9 | {
10 | public static class ReflectExt
11 | {
12 | public static OpCode[] GetOpCodes(byte[] data)
13 | {
14 | var opCodes = typeof(OpCodes)
15 | .GetFields()
16 | .Select(fi => (OpCode)fi.GetValue(null));
17 | return data.Select(op =>
18 | opCodes.FirstOrDefault(opCode => opCode.Value == op)).Where(p=>p!=null).ToArray();
19 | }
20 | public static string DumpMethod(Delegate method)
21 | {
22 | // For aggregating our response
23 | StringBuilder sb = new StringBuilder();
24 |
25 | // First we need to extract out the raw IL
26 | var mb = method.Method.GetMethodBody();
27 | var il = mb.GetILAsByteArray();
28 |
29 | // We'll also need a full set of the IL opcodes so we
30 | // can remap them over our method body
31 | var opCodes = typeof(System.Reflection.Emit.OpCodes)
32 | .GetFields()
33 | .Select(fi => (System.Reflection.Emit.OpCode)fi.GetValue(null));
34 |
35 | //opCodes.Dump();
36 |
37 | // For each byte in our method body, try to match it to an opcode
38 | var mappedIL = il.Select(op =>
39 | opCodes.FirstOrDefault(opCode => opCode.Value == op));
40 |
41 | // OpCode/Operand parsing:
42 | // Some opcodes have no operands, some use ints, etc.
43 | // let's try to cover all cases
44 | var ilWalker = mappedIL.GetEnumerator();
45 | while (ilWalker.MoveNext())
46 | {
47 | var mappedOp = ilWalker.Current;
48 | if (mappedOp.OperandType != OperandType.InlineNone)
49 | {
50 | // For operand inference:
51 | // MOST operands are 32 bit,
52 | // so we'll start there
53 | var byteCount = 4;
54 | long operand = 0;
55 | string token = string.Empty;
56 |
57 | // For metadata token resolution
58 | var module = method.Method.Module;
59 | Func tokenResolver = tkn => string.Empty;
60 | switch (mappedOp.OperandType)
61 | {
62 | // These are all 32bit metadata tokens
63 | case OperandType.InlineMethod:
64 | tokenResolver = tkn =>
65 | {
66 | var resMethod = module.SafeResolveMethod((int)tkn);
67 | return string.Format("({0}())", resMethod == null ? "unknown" : resMethod.Name);
68 | };
69 | break;
70 | case OperandType.InlineField:
71 | tokenResolver = tkn =>
72 | {
73 | var field = module.SafeResolveField((int)tkn);
74 | return string.Format("({0})", field == null ? "unknown" : field.Name);
75 | };
76 | break;
77 | case OperandType.InlineSig:
78 | tokenResolver = tkn =>
79 | {
80 | var sigBytes = module.SafeResolveSignature((int)tkn);
81 | var catSig = string
82 | .Join(",", sigBytes);
83 | return string.Format("(SIG:{0})", catSig == null ? "unknown" : catSig);
84 | };
85 | break;
86 | case OperandType.InlineString:
87 | tokenResolver = tkn =>
88 | {
89 | var str = module.SafeResolveString((int)tkn);
90 | return string.Format("('{0}')", str == null ? "unknown" : str);
91 | };
92 | break;
93 | case OperandType.InlineType:
94 | tokenResolver = tkn =>
95 | {
96 | var type = module.SafeResolveType((int)tkn);
97 | return string.Format("(typeof({0}))", type == null ? "unknown" : type.Name);
98 | };
99 | break;
100 | // These are plain old 32bit operands
101 | case OperandType.InlineI:
102 | case OperandType.InlineBrTarget:
103 | case OperandType.InlineSwitch:
104 | case OperandType.ShortInlineR:
105 | break;
106 | // These are 64bit operands
107 | case OperandType.InlineI8:
108 | case OperandType.InlineR:
109 | byteCount = 8;
110 | break;
111 | // These are all 8bit values
112 | case OperandType.ShortInlineBrTarget:
113 | case OperandType.ShortInlineI:
114 | case OperandType.ShortInlineVar:
115 | byteCount = 1;
116 | break;
117 | }
118 | // Based on byte count, pull out the full operand
119 | for (int i = 0; i < byteCount; i++)
120 | {
121 | ilWalker.MoveNext();
122 | operand |= ((long)ilWalker.Current.Value) << (8 * i);
123 | }
124 |
125 | var resolved = tokenResolver((int)operand);
126 | resolved = string.IsNullOrEmpty(resolved) ? operand.ToString() : resolved;
127 | sb.AppendFormat("{0} {1}",
128 | mappedOp.Name,
129 | resolved)
130 | .AppendLine();
131 | }
132 | else
133 | {
134 | sb.AppendLine(mappedOp.Name);
135 | }
136 | }
137 | return sb.ToString();
138 | }
139 | public static FieldInfo SafeResolveField(this Module m, int token)
140 | {
141 | FieldInfo fi;
142 | m.TryResolveField(token, out fi);
143 | return fi;
144 | }
145 | public static bool TryResolveField(this Module m, int token, out FieldInfo fi)
146 | {
147 | var ok = false;
148 | try { fi = m.ResolveField(token); ok = true; }
149 | catch { fi = null; }
150 | return ok;
151 | }
152 | public static MethodBase SafeResolveMethod(this Module m, int token)
153 | {
154 | MethodBase fi;
155 | m.TryResolveMethod(token, out fi);
156 | return fi;
157 | }
158 | public static bool TryResolveMethod(this Module m, int token, out MethodBase fi)
159 | {
160 | var ok = false;
161 | try { fi = m.ResolveMethod(token); ok = true; }
162 | catch { fi = null; }
163 | return ok;
164 | }
165 | public static string SafeResolveString(this Module m, int token)
166 | {
167 | string fi;
168 | m.TryResolveString(token, out fi);
169 | return fi;
170 | }
171 | public static bool TryResolveString(this Module m, int token, out string fi)
172 | {
173 | var ok = false;
174 | try { fi = m.ResolveString(token); ok = true; }
175 | catch { fi = null; }
176 | return ok;
177 | }
178 | public static byte[] SafeResolveSignature(this Module m, int token)
179 | {
180 | byte[] fi;
181 | m.TryResolveSignature(token, out fi);
182 | return fi;
183 | }
184 | public static bool TryResolveSignature(this Module m, int token, out byte[] fi)
185 | {
186 | var ok = false;
187 | try { fi = m.ResolveSignature(token); ok = true; }
188 | catch { fi = null; }
189 | return ok;
190 | }
191 | public static Type SafeResolveType(this Module m, int token)
192 | {
193 | Type fi;
194 | m.TryResolveType(token, out fi);
195 | return fi;
196 | }
197 | public static bool TryResolveType(this Module m, int token, out Type fi)
198 | {
199 | var ok = false;
200 | try { fi = m.ResolveType(token); ok = true; }
201 | catch { fi = null; }
202 | return ok;
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/AutoCopyLib/OldExpressionVisitor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Linq.Expressions;
5 |
6 | namespace AutoCopyLib
7 | {
8 | #region OldExpressionVisitor
9 | [Obsolete("使用System.Core库的System.Linq.Expressions.ExpressionVisitor类")]
10 | public abstract class OldExpressionVisitor
11 | {
12 | protected OldExpressionVisitor()
13 | {
14 | }
15 |
16 | protected virtual Expression Visit(Expression exp)
17 | {
18 | if (exp == null)
19 | return exp;
20 | switch (exp.NodeType)
21 | {
22 | case ExpressionType.Negate:
23 | case ExpressionType.NegateChecked:
24 | case ExpressionType.Not:
25 | case ExpressionType.Convert:
26 | case ExpressionType.ConvertChecked:
27 | case ExpressionType.ArrayLength:
28 | case ExpressionType.Quote:
29 | case ExpressionType.TypeAs:
30 | return this.VisitUnary((UnaryExpression)exp);
31 | case ExpressionType.Add:
32 | case ExpressionType.AddChecked:
33 | case ExpressionType.Subtract:
34 | case ExpressionType.SubtractChecked:
35 | case ExpressionType.Multiply:
36 | case ExpressionType.MultiplyChecked:
37 | case ExpressionType.Divide:
38 | case ExpressionType.Modulo:
39 | case ExpressionType.And:
40 | case ExpressionType.AndAlso:
41 | case ExpressionType.Or:
42 | case ExpressionType.OrElse:
43 | case ExpressionType.LessThan:
44 | case ExpressionType.LessThanOrEqual:
45 | case ExpressionType.GreaterThan:
46 | case ExpressionType.GreaterThanOrEqual:
47 | case ExpressionType.Equal:
48 | case ExpressionType.NotEqual:
49 | case ExpressionType.Coalesce:
50 | case ExpressionType.ArrayIndex:
51 | case ExpressionType.RightShift:
52 | case ExpressionType.LeftShift:
53 | case ExpressionType.ExclusiveOr:
54 | return this.VisitBinary((BinaryExpression)exp);
55 | case ExpressionType.TypeIs:
56 | return this.VisitTypeIs((TypeBinaryExpression)exp);
57 | case ExpressionType.Conditional:
58 | return this.VisitConditional((ConditionalExpression)exp);
59 | case ExpressionType.Constant:
60 | return this.VisitConstant((ConstantExpression)exp);
61 | case ExpressionType.Parameter:
62 | return this.VisitParameter((ParameterExpression)exp);
63 | case ExpressionType.MemberAccess:
64 | return this.VisitMemberAccess((MemberExpression)exp);
65 | case ExpressionType.Call:
66 | return this.VisitMethodCall((MethodCallExpression)exp);
67 | case ExpressionType.Lambda:
68 | return this.VisitLambda((LambdaExpression)exp);
69 | case ExpressionType.New:
70 | return this.VisitNew((NewExpression)exp);
71 | case ExpressionType.NewArrayInit:
72 | case ExpressionType.NewArrayBounds:
73 | return this.VisitNewArray((NewArrayExpression)exp);
74 | case ExpressionType.Invoke:
75 | return this.VisitInvocation((InvocationExpression)exp);
76 | case ExpressionType.MemberInit:
77 | return this.VisitMemberInit((MemberInitExpression)exp);
78 | case ExpressionType.ListInit:
79 | return this.VisitListInit((ListInitExpression)exp);
80 | default:
81 | throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType));
82 | }
83 | }
84 |
85 | protected virtual MemberBinding VisitBinding(MemberBinding binding)
86 | {
87 | switch (binding.BindingType)
88 | {
89 | case MemberBindingType.Assignment:
90 | return this.VisitMemberAssignment((MemberAssignment)binding);
91 | case MemberBindingType.MemberBinding:
92 | return this.VisitMemberMemberBinding((MemberMemberBinding)binding);
93 | case MemberBindingType.ListBinding:
94 | return this.VisitMemberListBinding((MemberListBinding)binding);
95 | default:
96 | throw new Exception(string.Format("Unhandled binding type '{0}'", binding.BindingType));
97 | }
98 | }
99 |
100 | protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
101 | {
102 | ReadOnlyCollection arguments = this.VisitExpressionList(initializer.Arguments);
103 | if (arguments != initializer.Arguments)
104 | {
105 | return Expression.ElementInit(initializer.AddMethod, arguments);
106 | }
107 | return initializer;
108 | }
109 |
110 | protected virtual Expression VisitUnary(UnaryExpression u)
111 | {
112 | Expression operand = this.Visit(u.Operand);
113 | if (operand != u.Operand)
114 | {
115 | return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method);
116 | }
117 | return u;
118 | }
119 |
120 | protected virtual Expression VisitBinary(BinaryExpression b)
121 | {
122 | Expression left = this.Visit(b.Left);
123 | Expression right = this.Visit(b.Right);
124 | Expression conversion = this.Visit(b.Conversion);
125 | if (left != b.Left || right != b.Right || conversion != b.Conversion)
126 | {
127 | if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null)
128 | return Expression.Coalesce(left, right, conversion as LambdaExpression);
129 | else
130 | return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
131 | }
132 | return b;
133 | }
134 |
135 | protected virtual Expression VisitTypeIs(TypeBinaryExpression b)
136 | {
137 | Expression expr = this.Visit(b.Expression);
138 | if (expr != b.Expression)
139 | {
140 | return Expression.TypeIs(expr, b.TypeOperand);
141 | }
142 | return b;
143 | }
144 |
145 | protected virtual Expression VisitConstant(ConstantExpression c)
146 | {
147 | return c;
148 | }
149 |
150 | protected virtual Expression VisitConditional(ConditionalExpression c)
151 | {
152 | Expression test = this.Visit(c.Test);
153 | Expression ifTrue = this.Visit(c.IfTrue);
154 | Expression ifFalse = this.Visit(c.IfFalse);
155 | if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse)
156 | {
157 | return Expression.Condition(test, ifTrue, ifFalse);
158 | }
159 | return c;
160 | }
161 |
162 | protected virtual Expression VisitParameter(ParameterExpression p)
163 | {
164 | return p;
165 | }
166 |
167 | protected virtual Expression VisitMemberAccess(MemberExpression m)
168 | {
169 | Expression exp = this.Visit(m.Expression);
170 | if (exp != m.Expression)
171 | {
172 | return Expression.MakeMemberAccess(exp, m.Member);
173 | }
174 | return m;
175 | }
176 |
177 | protected virtual Expression VisitMethodCall(MethodCallExpression m)
178 | {
179 | Expression obj = this.Visit(m.Object);
180 | IEnumerable args = this.VisitExpressionList(m.Arguments);
181 | if (obj != m.Object || args != m.Arguments)
182 | {
183 | return Expression.Call(obj, m.Method, args);
184 | }
185 | return m;
186 | }
187 |
188 | protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection original)
189 | {
190 | List list = null;
191 | for (int i = 0, n = original.Count; i < n; i++)
192 | {
193 | Expression p = this.Visit(original[i]);
194 | if (list != null)
195 | {
196 | list.Add(p);
197 | }
198 | else if (p != original[i])
199 | {
200 | list = new List(n);
201 | for (int j = 0; j < i; j++)
202 | {
203 | list.Add(original[j]);
204 | }
205 | list.Add(p);
206 | }
207 | }
208 | if (list != null)
209 | {
210 | return list.AsReadOnly();
211 | }
212 | return original;
213 | }
214 |
215 | protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment)
216 | {
217 | Expression e = this.Visit(assignment.Expression);
218 | if (e != assignment.Expression)
219 | {
220 | return Expression.Bind(assignment.Member, e);
221 | }
222 | return assignment;
223 | }
224 |
225 | protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
226 | {
227 | IEnumerable bindings = this.VisitBindingList(binding.Bindings);
228 | if (bindings != binding.Bindings)
229 | {
230 | return Expression.MemberBind(binding.Member, bindings);
231 | }
232 | return binding;
233 | }
234 |
235 | protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
236 | {
237 | IEnumerable initializers = this.VisitElementInitializerList(binding.Initializers);
238 | if (initializers != binding.Initializers)
239 | {
240 | return Expression.ListBind(binding.Member, initializers);
241 | }
242 | return binding;
243 | }
244 |
245 | protected virtual IEnumerable VisitBindingList(ReadOnlyCollection original)
246 | {
247 | List list = null;
248 | for (int i = 0, n = original.Count; i < n; i++)
249 | {
250 | MemberBinding b = this.VisitBinding(original[i]);
251 | if (list != null)
252 | {
253 | list.Add(b);
254 | }
255 | else if (b != original[i])
256 | {
257 | list = new List(n);
258 | for (int j = 0; j < i; j++)
259 | {
260 | list.Add(original[j]);
261 | }
262 | list.Add(b);
263 | }
264 | }
265 | if (list != null)
266 | return list;
267 | return original;
268 | }
269 |
270 | protected virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original)
271 | {
272 | List list = null;
273 | for (int i = 0, n = original.Count; i < n; i++)
274 | {
275 | ElementInit init = this.VisitElementInitializer(original[i]);
276 | if (list != null)
277 | {
278 | list.Add(init);
279 | }
280 | else if (init != original[i])
281 | {
282 | list = new List(n);
283 | for (int j = 0; j < i; j++)
284 | {
285 | list.Add(original[j]);
286 | }
287 | list.Add(init);
288 | }
289 | }
290 | if (list != null)
291 | return list;
292 | return original;
293 | }
294 |
295 | protected virtual Expression VisitLambda(LambdaExpression lambda)
296 | {
297 | Expression body = this.Visit(lambda.Body);
298 | if (body != lambda.Body)
299 | {
300 | return Expression.Lambda(lambda.Type, body, lambda.Parameters);
301 | }
302 | return lambda;
303 | }
304 |
305 | protected virtual NewExpression VisitNew(NewExpression nex)
306 | {
307 | IEnumerable args = this.VisitExpressionList(nex.Arguments);
308 | if (args != nex.Arguments)
309 | {
310 | if (nex.Members != null)
311 | return Expression.New(nex.Constructor, args, nex.Members);
312 | else
313 | return Expression.New(nex.Constructor, args);
314 | }
315 | return nex;
316 | }
317 |
318 | protected virtual Expression VisitMemberInit(MemberInitExpression init)
319 | {
320 | NewExpression n = this.VisitNew(init.NewExpression);
321 | IEnumerable bindings = this.VisitBindingList(init.Bindings);
322 | if (n != init.NewExpression || bindings != init.Bindings)
323 | {
324 | return Expression.MemberInit(n, bindings);
325 | }
326 | return init;
327 | }
328 |
329 | protected virtual Expression VisitListInit(ListInitExpression init)
330 | {
331 | NewExpression n = this.VisitNew(init.NewExpression);
332 | IEnumerable initializers = this.VisitElementInitializerList(init.Initializers);
333 | if (n != init.NewExpression || initializers != init.Initializers)
334 | {
335 | return Expression.ListInit(n, initializers);
336 | }
337 | return init;
338 | }
339 |
340 | protected virtual Expression VisitNewArray(NewArrayExpression na)
341 | {
342 | IEnumerable exprs = this.VisitExpressionList(na.Expressions);
343 | if (exprs != na.Expressions)
344 | {
345 | if (na.NodeType == ExpressionType.NewArrayInit)
346 | {
347 | return Expression.NewArrayInit(na.Type.GetElementType(), exprs);
348 | }
349 | else
350 | {
351 | return Expression.NewArrayBounds(na.Type.GetElementType(), exprs);
352 | }
353 | }
354 | return na;
355 | }
356 |
357 | protected virtual Expression VisitInvocation(InvocationExpression iv)
358 | {
359 | IEnumerable args = this.VisitExpressionList(iv.Arguments);
360 | Expression expr = this.Visit(iv.Expression);
361 | if (args != iv.Arguments || expr != iv.Expression)
362 | {
363 | return Expression.Invoke(expr, args);
364 | }
365 | return iv;
366 | }
367 | }
368 | #endregion
369 | }
370 |
--------------------------------------------------------------------------------
/AutoCopyLib/AutoCopy.cs:
--------------------------------------------------------------------------------
1 | using AutoCopyLib.Attributes;
2 | using AutoCopyLib.Utilities;
3 | using AutoCopyLib.Visitors;
4 | using DelegateDecompiler;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Linq.Expressions;
9 | using System.Reflection;
10 | using System.Reflection.Emit;
11 |
12 | namespace AutoCopyLib
13 | {
14 | public class AutoCopy
15 | {
16 | public static AutoCopy CreateMap()
17 | {
18 | return new AutoCopy();
19 | }
20 | }
21 | public partial class AutoCopy
22 | {
23 | private static ConstantExpression ReturnTrue = Expression.Constant(true, typeof(bool));
24 | private static ConstantExpression ReturnFalse = Expression.Constant(false, typeof(bool));
25 | delegate bool RefFunc(ref TDest dest, TSource src, out string errMsg);
26 | internal AutoCopy()
27 | {
28 | var p1 = Expression.Parameter(typeof(TDest).MakeByRefType(), "dest");
29 | var p2 = Expression.Parameter(typeof(TSource), "src");
30 | var p3 = Expression.Parameter(typeof(string).MakeByRefType(), "errMsg");
31 | parameterTuple = new ParameterTuple(p1, p2, p3);
32 | opt = new Option(parameterTuple);
33 | }
34 | private RefFunc m_func;
35 | private Option opt = null;
36 | private ParameterTuple parameterTuple = null;
37 | private Dictionary _map = new Dictionary();
38 | private NullsafeQueryRewriter nullsafeQueryRewriter = new NullsafeQueryRewriter();
39 | private Func nullsafeQueryFunc = null;
40 | private Dictionary _typeConvertMap = new Dictionary();
41 |
42 | public AutoCopy ForMember(Expression> dest, Func