sunkaixuan
3 years ago
4 changed files with 126 additions and 0 deletions
@ -0,0 +1,116 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
using System.Reflection.Emit; |
|||
using System.Text; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace SqlSugar |
|||
{ |
|||
public class ExpressionBuilderHelper |
|||
{ |
|||
public static Expression<Func<T, object>> CreateNewFields<T>(EntityInfo entity,List<string> propertyNames) |
|||
{ |
|||
Type sourceType = typeof(T); |
|||
Dictionary<string, PropertyInfo> sourceProperties = entity.Columns.Where(it=> propertyNames.Contains(it.PropertyName)).ToDictionary(it=>it.PropertyName,it=>it.PropertyInfo); |
|||
|
|||
Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.Values); |
|||
|
|||
ParameterExpression sourceItem = Expression.Parameter(sourceType, "t"); |
|||
IEnumerable<MemberBinding> bindings = dynamicType.GetRuntimeProperties().Select(p => Expression.Bind(p, Expression.Property(sourceItem, sourceProperties[p.Name]))).OfType<MemberBinding>(); |
|||
|
|||
return Expression.Lambda<Func<T, object>>(Expression.MemberInit( |
|||
Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem); |
|||
} |
|||
} |
|||
internal static class LinqRuntimeTypeBuilder |
|||
{ |
|||
private static readonly AssemblyName AssemblyName = new AssemblyName() { Name = "LinqRuntimeTypes4iTheoChan" }; |
|||
private static readonly ModuleBuilder ModuleBuilder; |
|||
private static readonly Dictionary<string, Type> BuiltTypes = new Dictionary<string, Type>(); |
|||
|
|||
static LinqRuntimeTypeBuilder() |
|||
{ |
|||
ModuleBuilder = AssemblyBuilder.DefineDynamicAssembly(AssemblyName, AssemblyBuilderAccess.Run).DefineDynamicModule(AssemblyName.Name); |
|||
} |
|||
|
|||
private static string GetTypeKey(Dictionary<string, Type> properties) |
|||
{ |
|||
//TODO: optimize the type caching -- if fields are simply reordered, that doesn't mean that they're actually different types, so this needs to be smarter
|
|||
string key = string.Empty; |
|||
foreach (var prop in properties) |
|||
key += prop.Key + ";" + prop.Value.Name + ";"; |
|||
|
|||
return key; |
|||
} |
|||
|
|||
private const MethodAttributes RuntimeGetSetAttrs = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; |
|||
|
|||
public static Type BuildDynamicType(Dictionary<string, Type> properties) |
|||
{ |
|||
if (null == properties) |
|||
throw new ArgumentNullException(nameof(properties)); |
|||
if (0 == properties.Count) |
|||
throw new ArgumentOutOfRangeException(nameof(properties), "fields must have at least 1 field definition"); |
|||
|
|||
try |
|||
{ |
|||
// Acquires an exclusive lock on the specified object.
|
|||
Monitor.Enter(BuiltTypes); |
|||
string className = GetTypeKey(properties); |
|||
|
|||
if (BuiltTypes.ContainsKey(className)) |
|||
return BuiltTypes[className]; |
|||
|
|||
TypeBuilder typeBdr = ModuleBuilder.DefineType(className, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable); |
|||
|
|||
foreach (var prop in properties) |
|||
{ |
|||
var propertyBdr = typeBdr.DefineProperty(name: prop.Key, attributes: PropertyAttributes.None, returnType: prop.Value, parameterTypes: null); |
|||
var fieldBdr = typeBdr.DefineField("itheofield_" + prop.Key, prop.Value, FieldAttributes.Private); |
|||
|
|||
MethodBuilder getMethodBdr = typeBdr.DefineMethod("get_" + prop.Key, RuntimeGetSetAttrs, prop.Value, Type.EmptyTypes); |
|||
ILGenerator getIL = getMethodBdr.GetILGenerator(); |
|||
getIL.Emit(OpCodes.Ldarg_0); |
|||
getIL.Emit(OpCodes.Ldfld, fieldBdr); |
|||
getIL.Emit(OpCodes.Ret); |
|||
|
|||
MethodBuilder setMethodBdr = typeBdr.DefineMethod("set_" + prop.Key, RuntimeGetSetAttrs, null, new Type[] { prop.Value }); |
|||
ILGenerator setIL = setMethodBdr.GetILGenerator(); |
|||
setIL.Emit(OpCodes.Ldarg_0); |
|||
setIL.Emit(OpCodes.Ldarg_1); |
|||
setIL.Emit(OpCodes.Stfld, fieldBdr); |
|||
setIL.Emit(OpCodes.Ret); |
|||
|
|||
propertyBdr.SetGetMethod(getMethodBdr); |
|||
propertyBdr.SetSetMethod(setMethodBdr); |
|||
} |
|||
|
|||
BuiltTypes[className] = typeBdr.CreateType(); |
|||
|
|||
return BuiltTypes[className]; |
|||
} |
|||
catch |
|||
{ |
|||
throw; |
|||
} |
|||
finally |
|||
{ |
|||
Monitor.Exit(BuiltTypes); |
|||
} |
|||
} |
|||
|
|||
private static string GetTypeKey(IEnumerable<PropertyInfo> properties) |
|||
{ |
|||
return GetTypeKey(properties.ToDictionary(f => f.Name, f => f.PropertyType)); |
|||
} |
|||
|
|||
public static Type GetDynamicType(IEnumerable<PropertyInfo> properties) |
|||
{ |
|||
return BuildDynamicType(properties.ToDictionary(f => f.Name, f => f.PropertyType)); |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue