1+ using FreeSql . DataAnnotations ;
2+ using System ;
3+ using System . Collections ;
4+ using System . Collections . Concurrent ;
5+ using System . Collections . Generic ;
6+ using System . Linq ;
7+ using System . Linq . Expressions ;
8+ using System . Reflection ;
9+ using System . Reflection . Emit ;
10+ using System . Security . Cryptography ;
11+ using FreeSql . Internal . Model ;
12+ using System . Text ;
13+
14+ namespace FreeSql . Internal
15+ {
16+ #if net40 || NETSTANDARD2_0
17+ #else
18+ public class DynamicCompileBuilder
19+ {
20+ private string _className = string . Empty ;
21+ private TableAttribute _tableAttribute = null ;
22+ private List < DynamicPropertyInfo > _properties = new List < DynamicPropertyInfo > ( ) ;
23+
24+ /// <summary>
25+ /// 配置Class
26+ /// </summary>
27+ /// <param name="className">类名</param>
28+ /// <param name="tableAttribute">类标记的特性[Table(Name = "xxx")]</param>
29+ /// <returns></returns>
30+ public DynamicCompileBuilder SetClass ( string className , TableAttribute tableAttribute )
31+ {
32+ _className = className ;
33+ _tableAttribute = tableAttribute ;
34+ return this ;
35+ }
36+
37+ /// <summary>
38+ /// 配置属性
39+ /// </summary>
40+ /// <param name="propertyName">属性名称</param>
41+ /// <param name="propertyType">属性类型</param>
42+ /// <param name="attributes">属性标记的特性-支持多个</param>
43+ /// <returns></returns>
44+ public DynamicCompileBuilder Property ( string propertyName , Type propertyType , params Attribute [ ] attributes )
45+ {
46+ _properties . Add ( new DynamicPropertyInfo ( )
47+ {
48+ PropertyName = propertyName ,
49+ PropertyType = propertyType ,
50+ Attributes = attributes
51+ } ) ;
52+ return this ;
53+ }
54+
55+ private void SetTableAttribute ( ref TypeBuilder typeBuilder )
56+ {
57+ var classCtorInfo = typeof ( TableAttribute ) . GetConstructor ( new Type [ ] { } ) ;
58+ var propertyInfos = typeof ( TableAttribute ) . GetProperties ( ) . Where ( p => p . CanWrite == true ) . ToArray ( ) ;
59+ if ( _tableAttribute == null )
60+ {
61+ return ;
62+ }
63+
64+ var propertyValues = new ArrayList ( ) ;
65+ foreach ( var propertyInfo in _tableAttribute . GetType ( ) . GetProperties ( ) . Where ( p => p . CanWrite == true ) )
66+ {
67+ propertyValues . Add ( propertyInfo . GetValue ( _tableAttribute ) ) ;
68+ }
69+
70+ var customAttributeBuilder =
71+ new CustomAttributeBuilder ( classCtorInfo , new object [ 0 ] , propertyInfos , propertyValues . ToArray ( ) ) ;
72+ typeBuilder . SetCustomAttribute ( customAttributeBuilder ) ;
73+ }
74+
75+ private void SetPropertys ( ref TypeBuilder typeBuilder )
76+ {
77+ foreach ( var pinfo in _properties )
78+ {
79+ var propertyName = pinfo . PropertyName ;
80+ var propertyType = pinfo ? . PropertyType ?? typeof ( object ) ;
81+ //设置字段
82+ var field = typeBuilder . DefineField ( $ "_{ FirstCharToLower ( propertyName ) } ", propertyType ,
83+ FieldAttributes . Private ) ;
84+ var firstCharToUpper = FirstCharToUpper ( propertyName ) ;
85+ //设置属性方法
86+ var methodGet = typeBuilder . DefineMethod ( $ "Get{ firstCharToUpper } ", MethodAttributes . Public ,
87+ propertyType , null ) ;
88+ var methodSet = typeBuilder . DefineMethod ( $ "Set{ firstCharToUpper } ", MethodAttributes . Public , null ,
89+ new Type [ ] { propertyType } ) ;
90+
91+ var ilOfGet = methodGet . GetILGenerator ( ) ;
92+ ilOfGet . Emit ( OpCodes . Ldarg_0 ) ;
93+ ilOfGet . Emit ( OpCodes . Ldfld , field ) ;
94+ ilOfGet . Emit ( OpCodes . Ret ) ;
95+
96+ var ilOfSet = methodSet . GetILGenerator ( ) ;
97+ ilOfSet . Emit ( OpCodes . Ldarg_0 ) ;
98+ ilOfSet . Emit ( OpCodes . Ldarg_1 ) ;
99+ ilOfSet . Emit ( OpCodes . Stfld , field ) ;
100+ ilOfSet . Emit ( OpCodes . Ret ) ;
101+
102+ //设置属性
103+ var propertyBuilder =
104+ typeBuilder . DefineProperty ( propertyName , PropertyAttributes . None , propertyType , null ) ;
105+ propertyBuilder . SetGetMethod ( methodGet ) ;
106+ propertyBuilder . SetSetMethod ( methodSet ) ;
107+
108+ foreach ( var pinfoAttribute in pinfo . Attributes )
109+ {
110+ //设置特性
111+ SetPropertyAttribute ( ref propertyBuilder , pinfoAttribute ) ;
112+ }
113+ }
114+ }
115+
116+ private void SetPropertyAttribute < T > ( ref PropertyBuilder propertyBuilder , T tAttribute )
117+ {
118+ if ( tAttribute == null )
119+ return ;
120+
121+ var propertyValues = new ArrayList ( ) ;
122+ foreach ( var propertyInfo in tAttribute . GetType ( ) . GetProperties ( ) . Where ( p => p . CanWrite == true ) )
123+ {
124+ propertyValues . Add ( propertyInfo . GetValue ( tAttribute ) ) ;
125+ }
126+
127+ var propertyInfos = tAttribute . GetType ( ) . GetProperties ( ) . Where ( p => p . CanWrite == true ) . ToArray ( ) ;
128+ var constructor = tAttribute . GetType ( ) . GetConstructor ( new Type [ ] { } ) ;
129+ var customAttributeBuilder =
130+ new CustomAttributeBuilder ( constructor , new object [ 0 ] , propertyInfos , propertyValues . ToArray ( ) ) ;
131+ propertyBuilder . SetCustomAttribute ( customAttributeBuilder ) ;
132+ }
133+
134+ /// <summary>
135+ /// Emit动态创建出Class - Type
136+ /// </summary>
137+ /// <returns></returns>
138+ public Type Build ( )
139+ {
140+ //初始化AssemblyName的一个实例
141+ var assemblyName = new AssemblyName ( "FreeSql.DynamicCompileBuilder" ) ;
142+ //设置程序集的名称
143+ var defineDynamicAssembly = AssemblyBuilder . DefineDynamicAssembly ( assemblyName , AssemblyBuilderAccess . Run ) ;
144+ //动态在程序集内创建一个模块
145+ var defineDynamicModule =
146+ defineDynamicAssembly . DefineDynamicModule ( "FreeSql.DynamicCompileBuilder.Dynamics" ) ;
147+ //动态的在模块内创建一个类
148+ var typeBuilder = defineDynamicModule . DefineType ( _className , TypeAttributes . Public | TypeAttributes . Class ) ;
149+
150+ //设置TableAttribute
151+ SetTableAttribute ( ref typeBuilder ) ;
152+
153+ //设置属性
154+ SetPropertys ( ref typeBuilder ) ;
155+
156+ //创建类的Type对象
157+ return typeBuilder . CreateType ( ) ;
158+ }
159+
160+ //委托缓存
161+ private static ConcurrentDictionary < string , Delegate >
162+ _delegateCache = new ConcurrentDictionary < string , Delegate > ( ) ;
163+
164+ //设置动态对象的属性值 使用FreeSql自带功能
165+ public static object CreateObjectByTypeByCodeFirst ( IFreeSql fsql , Type type ,
166+ Dictionary < string , object > porpertys )
167+ {
168+ if ( type == null )
169+ return null ;
170+ object istance = Activator . CreateInstance ( type ) ;
171+ if ( istance == null )
172+ return null ;
173+ var table = fsql . CodeFirst . GetTableByEntity ( type ) ;
174+ foreach ( var kv in porpertys )
175+ {
176+ table . ColumnsByCs [ kv . Key ] . SetValue ( istance , kv . Value ) ;
177+ }
178+
179+ return istance ;
180+ }
181+
182+ ////设置动态对象的属性值,使用表达式目录树
183+ //public static object CreateObjectByType(Type type, Dictionary<string, object> porpertys)
184+ //{
185+ // if (type == null)
186+ // return null;
187+ // object istance = Activator.CreateInstance(type);
188+ // if (istance == null)
189+ // return null;
190+ // //根据字典中的key确定缓存
191+ // var cacheKeyStr = string.Join("-", porpertys.Keys.OrderBy(s => s));
192+ // var cacheKey = Md5Encryption(cacheKeyStr);
193+ // var dynamicDelegate = _delegateCache.GetOrAdd(cacheKey, key =>
194+ // {
195+ // //表达式目录树构建委托
196+ // var typeParam = Expression.Parameter(type);
197+ // var dicParamType = typeof(Dictionary<string, object>);
198+ // var dicParam = Expression.Parameter(dicParamType);
199+ // var exps = new List<Expression>();
200+ // var tempRef = Expression.Variable(typeof(object));
201+ // foreach (var pinfo in porpertys)
202+ // {
203+ // var propertyInfo = type.GetProperty(pinfo.Key);
204+ // if (propertyInfo == null)
205+ // continue;
206+ // var propertyName = Expression.Constant(pinfo.Key, typeof(string));
207+ // exps.Add(Expression.Call(dicParam, dicParamType.GetMethod("TryGetValue"), propertyName, tempRef));
208+ // exps.Add(Expression.Assign(Expression.MakeMemberAccess(typeParam, propertyInfo),
209+ // Expression.Convert(tempRef, propertyInfo.PropertyType)));
210+ // exps.Add(Expression.Assign(tempRef, Expression.Default(typeof(object))));
211+ // }
212+
213+ // var returnTarget = Expression.Label(type);
214+ // exps.Add(Expression.Return(returnTarget, typeParam));
215+ // exps.Add(Expression.Label(returnTarget, Expression.Default(type)));
216+ // var block = Expression.Block(new[] { tempRef }, exps);
217+ // var @delegate = Expression.Lambda(block, typeParam, dicParam).Compile();
218+ // return @delegate;
219+ // });
220+ // var dynamicInvoke = dynamicDelegate.DynamicInvoke(istance, porpertys);
221+ // return dynamicInvoke;
222+ //}
223+
224+ /// <summary>
225+ /// 首字母小写
226+ /// </summary>
227+ /// <param name="input"></param>
228+ /// <returns></returns>
229+ private string FirstCharToLower ( string input )
230+ {
231+ if ( string . IsNullOrEmpty ( input ) )
232+ return input ;
233+ string str = input . First ( ) . ToString ( ) . ToLower ( ) + input . Substring ( 1 ) ;
234+ return str ;
235+ }
236+
237+ /// <summary>
238+ /// 首字母大写
239+ /// </summary>
240+ /// <param name="input"></param>
241+ /// <returns></returns>
242+ private string FirstCharToUpper ( string input )
243+ {
244+ if ( string . IsNullOrEmpty ( input ) )
245+ return input ;
246+ string str = input . First ( ) . ToString ( ) . ToUpper ( ) + input . Substring ( 1 ) ;
247+ return str ;
248+ }
249+
250+ private static string Md5Encryption ( string inputStr )
251+ {
252+ var result = string . Empty ;
253+ //32位大写
254+ using ( var md5 = MD5 . Create ( ) )
255+ {
256+ var resultBytes = md5 . ComputeHash ( Encoding . UTF8 . GetBytes ( inputStr ) ) ;
257+ result = BitConverter . ToString ( resultBytes ) ;
258+ }
259+
260+ return result ;
261+ }
262+ }
263+ #endif
264+ internal class DynamicPropertyInfo
265+ {
266+ public string PropertyName { get ; set ; } = string . Empty ;
267+ public Type PropertyType { get ; set ; }
268+ public Attribute [ ] Attributes { get ; set ; }
269+ }
270+ }
0 commit comments