Skip to content

Commit 2945f95

Browse files
authored
Merge pull request #1505 from d4ilys/master
- DynamicEntity拆分独立nuget包
2 parents 8ab7e76 + d26ad21 commit 2945f95

File tree

10 files changed

+381
-139
lines changed

10 files changed

+381
-139
lines changed

FreeSql/Internal/DynamicCompileBuilder.cs renamed to Extensions/FreeSql.Extensions.DynamicEntity/DynamicCompileBuilder.cs

Lines changed: 48 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
1-
using FreeSql.DataAnnotations;
2-
using System;
1+
using System;
32
using System.Collections;
4-
using System.Collections.Concurrent;
53
using System.Collections.Generic;
64
using System.Linq;
7-
using System.Linq.Expressions;
85
using System.Reflection;
96
using System.Reflection.Emit;
107
using System.Security.Cryptography;
11-
using FreeSql.Internal.Model;
128
using System.Text;
139

14-
namespace FreeSql.Internal
10+
namespace FreeSql.Extensions.DynamicEntity
1511
{
16-
#if net40 || NETSTANDARD2_0
17-
#else
12+
/// <summary>
13+
/// 动态创建实体类型
14+
/// </summary>
1815
public class DynamicCompileBuilder
1916
{
2017
private string _className = string.Empty;
2118
private Attribute[] _tableAttributes = null;
2219
private List<DynamicPropertyInfo> _properties = new List<DynamicPropertyInfo>();
20+
private Type _superClass = null;
2321

2422
/// <summary>
2523
/// 配置Class
2624
/// </summary>
2725
/// <param name="className">类名</param>
28-
/// <param name="attributes">类标记的特性[Table(Name = "xxx")]</param>
26+
/// <param name="attributes">类标记的特性[Table(Name = "xxx")] [Index(xxxx)]</param>
2927
/// <returns></returns>
30-
public DynamicCompileBuilder(string className, params Attribute[] attributes)
28+
public DynamicCompileBuilder Class(string className, params Attribute[] attributes)
3129
{
3230
_className = className;
3331
_tableAttributes = attributes;
32+
return this;
3433
}
3534

3635
/// <summary>
@@ -51,31 +50,59 @@ public DynamicCompileBuilder Property(string propertyName, Type propertyType, pa
5150
return this;
5251
}
5352

53+
/// <summary>
54+
/// 配置父类
55+
/// </summary>
56+
/// <param name="superClass">父类类型</param>
57+
/// <returns></returns>
58+
public DynamicCompileBuilder Extend(Type superClass)
59+
{
60+
_superClass = superClass;
61+
return this;
62+
}
63+
5464
private void SetTableAttribute(ref TypeBuilder typeBuilder)
5565
{
5666
if (_tableAttributes == null) return;
5767

58-
var propertyValues = new ArrayList();
5968
foreach (var tableAttribute in _tableAttributes)
6069
{
70+
var propertyValues = new ArrayList();
71+
6172
if (tableAttribute == null) continue;
6273

6374
var classCtorInfo = tableAttribute.GetType().GetConstructor(new Type[] { });
75+
6476
var propertyInfos = tableAttribute.GetType().GetProperties().Where(p => p.CanWrite == true).ToArray();
77+
6578
foreach (var propertyInfo in propertyInfos)
6679
propertyValues.Add(propertyInfo.GetValue(tableAttribute));
67-
68-
var customAttributeBuilder = new CustomAttributeBuilder(classCtorInfo, new object[0], propertyInfos, propertyValues.ToArray());
69-
typeBuilder.SetCustomAttribute(customAttributeBuilder);
80+
81+
//可能存在有参构造
82+
if (classCtorInfo == null)
83+
{
84+
var constructorTypes = propertyInfos.Select(p => p.PropertyType);
85+
classCtorInfo = tableAttribute.GetType().GetConstructor(constructorTypes.ToArray());
86+
var customAttributeBuilder = new CustomAttributeBuilder(classCtorInfo, propertyValues.ToArray());
87+
typeBuilder.SetCustomAttribute(customAttributeBuilder);
88+
}
89+
else
90+
{
91+
var customAttributeBuilder = new CustomAttributeBuilder(classCtorInfo, new object[0], propertyInfos,
92+
propertyValues.ToArray());
93+
typeBuilder.SetCustomAttribute(customAttributeBuilder);
94+
}
7095
}
7196
}
7297

7398
private void SetPropertys(ref TypeBuilder typeBuilder)
7499
{
75100
foreach (var pinfo in _properties)
76101
{
102+
if (pinfo == null)
103+
continue;
77104
var propertyName = pinfo.PropertyName;
78-
var propertyType = pinfo?.PropertyType ?? typeof(object);
105+
var propertyType = pinfo.PropertyType;
79106
//设置字段
80107
var field = typeBuilder.DefineField($"_{FirstCharToLower(propertyName)}", propertyType,
81108
FieldAttributes.Private);
@@ -98,7 +125,8 @@ private void SetPropertys(ref TypeBuilder typeBuilder)
98125
ilOfSet.Emit(OpCodes.Ret);
99126

100127
//设置属性
101-
var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
128+
var propertyBuilder =
129+
typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
102130
propertyBuilder.SetGetMethod(methodGet);
103131
propertyBuilder.SetSetMethod(methodSet);
104132

@@ -120,7 +148,8 @@ private void SetPropertyAttribute<T>(ref PropertyBuilder propertyBuilder, T tAtt
120148
foreach (var propertyInfo in propertyInfos)
121149
propertyValues.Add(propertyInfo.GetValue(tAttribute));
122150

123-
var customAttributeBuilder = new CustomAttributeBuilder(constructor, new object[0], propertyInfos, propertyValues.ToArray());
151+
var customAttributeBuilder =
152+
new CustomAttributeBuilder(constructor, new object[0], propertyInfos, propertyValues.ToArray());
124153
propertyBuilder.SetCustomAttribute(customAttributeBuilder);
125154
}
126155

@@ -138,7 +167,8 @@ public Type Build()
138167
var defineDynamicModule =
139168
defineDynamicAssembly.DefineDynamicModule("FreeSql.DynamicCompileBuilder.Dynamics");
140169
//动态的在模块内创建一个类
141-
var typeBuilder = defineDynamicModule.DefineType(_className, TypeAttributes.Public | TypeAttributes.Class);
170+
var typeBuilder =
171+
defineDynamicModule.DefineType(_className, TypeAttributes.Public | TypeAttributes.Class, _superClass);
142172

143173
//设置TableAttribute
144174
SetTableAttribute(ref typeBuilder);
@@ -150,70 +180,6 @@ public Type Build()
150180
return typeBuilder.CreateType();
151181
}
152182

153-
//委托缓存
154-
private static ConcurrentDictionary<string, Delegate>
155-
_delegateCache = new ConcurrentDictionary<string, Delegate>();
156-
157-
//设置动态对象的属性值 使用FreeSql自带功能
158-
public static object CreateObjectByTypeByCodeFirst(IFreeSql fsql, Type type,
159-
Dictionary<string, object> porpertys)
160-
{
161-
if (type == null)
162-
return null;
163-
object istance = Activator.CreateInstance(type);
164-
if (istance == null)
165-
return null;
166-
var table = fsql.CodeFirst.GetTableByEntity(type);
167-
foreach (var kv in porpertys)
168-
{
169-
table.ColumnsByCs[kv.Key].SetValue(istance, kv.Value);
170-
}
171-
172-
return istance;
173-
}
174-
175-
////设置动态对象的属性值,使用表达式目录树
176-
//public static object CreateObjectByType(Type type, Dictionary<string, object> porpertys)
177-
//{
178-
// if (type == null)
179-
// return null;
180-
// object istance = Activator.CreateInstance(type);
181-
// if (istance == null)
182-
// return null;
183-
// //根据字典中的key确定缓存
184-
// var cacheKeyStr = string.Join("-", porpertys.Keys.OrderBy(s => s));
185-
// var cacheKey = Md5Encryption(cacheKeyStr);
186-
// var dynamicDelegate = _delegateCache.GetOrAdd(cacheKey, key =>
187-
// {
188-
// //表达式目录树构建委托
189-
// var typeParam = Expression.Parameter(type);
190-
// var dicParamType = typeof(Dictionary<string, object>);
191-
// var dicParam = Expression.Parameter(dicParamType);
192-
// var exps = new List<Expression>();
193-
// var tempRef = Expression.Variable(typeof(object));
194-
// foreach (var pinfo in porpertys)
195-
// {
196-
// var propertyInfo = type.GetProperty(pinfo.Key);
197-
// if (propertyInfo == null)
198-
// continue;
199-
// var propertyName = Expression.Constant(pinfo.Key, typeof(string));
200-
// exps.Add(Expression.Call(dicParam, dicParamType.GetMethod("TryGetValue"), propertyName, tempRef));
201-
// exps.Add(Expression.Assign(Expression.MakeMemberAccess(typeParam, propertyInfo),
202-
// Expression.Convert(tempRef, propertyInfo.PropertyType)));
203-
// exps.Add(Expression.Assign(tempRef, Expression.Default(typeof(object))));
204-
// }
205-
206-
// var returnTarget = Expression.Label(type);
207-
// exps.Add(Expression.Return(returnTarget, typeParam));
208-
// exps.Add(Expression.Label(returnTarget, Expression.Default(type)));
209-
// var block = Expression.Block(new[] { tempRef }, exps);
210-
// var @delegate = Expression.Lambda(block, typeParam, dicParam).Compile();
211-
// return @delegate;
212-
// });
213-
// var dynamicInvoke = dynamicDelegate.DynamicInvoke(istance, porpertys);
214-
// return dynamicInvoke;
215-
//}
216-
217183
/// <summary>
218184
/// 首字母小写
219185
/// </summary>
@@ -260,5 +226,4 @@ class DynamicPropertyInfo
260226
public Attribute[] Attributes { get; set; }
261227
}
262228
}
263-
#endif
264229
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Linq.Expressions;
6+
using System.Security.Cryptography;
7+
using System.Text;
8+
9+
namespace FreeSql.Extensions.DynamicEntity
10+
{
11+
/// <summary>
12+
/// 动态创建对象帮助类
13+
/// </summary>
14+
public class DynamicCompileHelper
15+
{
16+
/// <summary>
17+
/// 动态构建Class - Type
18+
/// </summary>
19+
/// <returns></returns>
20+
public static DynamicCompileBuilder DynamicBuilder()
21+
{
22+
return new DynamicCompileBuilder();
23+
}
24+
25+
/// <summary>
26+
/// 委托缓存
27+
/// </summary>
28+
private static readonly ConcurrentDictionary<string, Delegate> DelegateCache =
29+
new ConcurrentDictionary<string, Delegate>();
30+
31+
/// <summary>
32+
/// 设置动态对象的属性值
33+
/// </summary>
34+
/// <param name="type"></param>
35+
/// <param name="porpertys"></param>
36+
/// <returns></returns>
37+
public static object CreateObjectByType(Type type, Dictionary<string, object> porpertys)
38+
{
39+
if (type == null)
40+
return null;
41+
object istance = Activator.CreateInstance(type);
42+
if (istance == null)
43+
return null;
44+
//根据key确定缓存
45+
var cacheKeyStr = string.Join("-", porpertys.Keys.OrderBy(s => s));
46+
var dicKey = Md5Encryption(cacheKeyStr);
47+
var cacheKey = $"{type.GetHashCode()}-{dicKey}";
48+
var dynamicDelegate = DelegateCache.GetOrAdd(cacheKey, key =>
49+
{
50+
//表达式目录树构建委托
51+
var typeParam = Expression.Parameter(type);
52+
var dicParamType = typeof(Dictionary<string, object>);
53+
var dicParam = Expression.Parameter(dicParamType);
54+
var exps = new List<Expression>();
55+
var tempRef = Expression.Variable(typeof(object));
56+
foreach (var pinfo in porpertys)
57+
{
58+
var propertyInfo = type.GetProperty(pinfo.Key);
59+
if (propertyInfo == null)
60+
continue;
61+
var propertyName = Expression.Constant(pinfo.Key, typeof(string));
62+
exps.Add(Expression.Call(dicParam, dicParamType.GetMethod("TryGetValue"), propertyName, tempRef));
63+
exps.Add(Expression.Assign(Expression.MakeMemberAccess(typeParam, propertyInfo),
64+
Expression.Convert(tempRef, propertyInfo.PropertyType)));
65+
exps.Add(Expression.Assign(tempRef, Expression.Default(typeof(object))));
66+
}
67+
68+
var returnTarget = Expression.Label(type);
69+
exps.Add(Expression.Return(returnTarget, typeParam));
70+
exps.Add(Expression.Label(returnTarget, Expression.Default(type)));
71+
var block = Expression.Block(new[] { tempRef }, exps);
72+
var @delegate = Expression.Lambda(block, typeParam, dicParam).Compile();
73+
return @delegate;
74+
});
75+
var dynamicInvoke = dynamicDelegate.DynamicInvoke(istance, porpertys);
76+
return dynamicInvoke;
77+
}
78+
79+
private static string Md5Encryption(string inputStr)
80+
{
81+
var result = string.Empty;
82+
//32位大写
83+
using (var md5 = MD5.Create())
84+
{
85+
var resultBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(inputStr));
86+
result = BitConverter.ToString(resultBytes);
87+
}
88+
89+
return result;
90+
}
91+
}
92+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>netstandard2.1;net451;net45;</TargetFrameworks>
5+
<GenerateDocumentationFile>True</GenerateDocumentationFile>
6+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
7+
<Authors>FreeSql;ncc;YeXiangQin;Daily</Authors>
8+
<Description>FreeSql 扩展包,可实现动态构建实体类,动态创建表.</Description>
9+
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
10+
<RepositoryUrl>https://github.com/2881099/FreeSql</RepositoryUrl>
11+
<RepositoryType>git</RepositoryType>
12+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
13+
<PackageTags>FreeSql;ORM</PackageTags>
14+
<PackageId>$(AssemblyName)</PackageId>
15+
<PackageIcon>logo.png</PackageIcon>
16+
<Title>$(AssemblyName)</Title>
17+
<IsPackable>true</IsPackable>
18+
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
19+
<SignAssembly>true</SignAssembly>
20+
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
21+
<DelaySign>false</DelaySign>
22+
<Version>3.2.694</Version> <PackageId>$(AssemblyName)</PackageId>
23+
<PackageIcon>logo.png</PackageIcon>
24+
<Title>$(AssemblyName)</Title>
25+
<IsPackable>true</IsPackable>
26+
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
27+
<SignAssembly>true</SignAssembly>
28+
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
29+
<DelaySign>false</DelaySign>
30+
<DocumentationFile>FreeSql.Extensions.DynamicEntity.xml</DocumentationFile>
31+
</PropertyGroup>
32+
<ItemGroup>
33+
<None Include="../../logo.png" Pack="true" PackagePath="\" />
34+
</ItemGroup>
35+
36+
<ItemGroup>
37+
<None Update="FreeSql.Extensions.DynamicEntity.xml">
38+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
39+
</None>
40+
</ItemGroup>
41+
42+
</Project>

0 commit comments

Comments
 (0)