簡體   English   中英

從反射切換到表達式樹

[英]Switching from Reflection to Expression trees

由於逐行反射相當昂貴,我一直在尋找構建和插入實體的更快的替代方案。 我做了一些關於這個主題的研究 ,並且還發現了一些性能比較 ,這似乎表明表達樹是要走的路。 我將如何重寫以下功能以利用此功能?

    public static void InsertTable(IEnumerable<DataTable> chunkedTable)
    {

        Parallel.ForEach(
            chunkedTable,
            new ParallelOptions
            {
                MaxDegreeOfParallelism = Convert.ToInt32(ConfigurationManager.AppSettings["MaxThreads"])
            },
            chunk =>
            {
                Realty_Records_ProdEntities entities = null;
                try
                {
                    entities = new Realty_Records_ProdEntities();
                    entities.Configuration.AutoDetectChangesEnabled = false;

                    foreach (DataRow dr in chunk.Rows)
                    {
                        var parcelToInsert = new Parcel();

                        foreach (DataColumn c in dr.Table.Columns)
                        {
                            var propertyInfo = parcelToInsert.GetType()
                                .GetProperty(
                                    c.ColumnName,
                                    BindingFlags.SetProperty | BindingFlags.IgnoreCase
                                    | BindingFlags.Public | BindingFlags.Instance);

                            propertyInfo?.SetValue(
                                parcelToInsert,
                                TaxDataFunction.ChangeType(
                                    dr[c.ColumnName],
                                    propertyInfo.PropertyType),
                                null);
                        }
                        entities.Parcels.Add(parcelToInsert);
                    }
                    entities.SaveChanges();
                }
                catch (Exception ex)
                {
                    TaxDataError.AddTaxApplicationLog(
                        TaxDataConstant.CategoryError,
                        ex.Source,
                        ex.Message,
                        ex.StackTrace);
                    throw;
                }
                finally
                {
                    entities?.Dispose();
                }
            });
    }

編輯:

以下是我最終實施的解決方案:

    private static readonly ConcurrentDictionary<SetterInfo, Action<object,object>> CachedSetters =
        new ConcurrentDictionary<SetterInfo, Action<object, object>>();

    private static readonly MethodInfo ChangeTypeMethod =
        ((Func<object, Type, object>) TaxDataFunction.ChangeType).Method;

    private static void SetProperty(object obj, string name, object value)
    {
        if (obj == null)
            return;

        var key = new SetterInfo(obj.GetType(), name);

        var setter = CachedSetters.GetOrAdd(key, CreateSetter);

        setter(obj, value);
    }

    private static Action<object, object> CreateSetter(SetterInfo info)
    {
        var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

        if (propertyInfo == null)
            return (s, v) => { };

        var objParameter = Expression.Parameter(typeof(object));
        var valueParameter = Expression.Parameter(typeof(object));

        var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, Expression.Constant(propertyInfo.PropertyType));

        var objCast = Expression.Convert(objParameter, info.Type);
        var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType);

        var property = Expression.Property(objCast, propertyInfo);

        var assignment = Expression.Assign(property, valueCast);

        var lambda = Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);

        return lambda.Compile();
    }

    private struct SetterInfo
    {
        public Type Type { get; }
        public string Name { get; }

        public SetterInfo(Type type, string name)
        {
            Type = type;
            Name = name;
        }
    }
static ConcurrentDictionary<string, Lazy<Action<object, object>>> CachedProperties = 
    new ConcurrentDictionary<string, Lazy<Action<object, object>>>();

static void SetProperty(object obj, string name, object value)
{
    if(obj==null)
        throw new ArgumentNullException("obj");
    Type objType = obj.GetType();
    string key =  objType.FullName + ":" + name;
    Action<object, object> f = 
    CachedProperties.GetOrAdd(key, k => 
        new Lazy<Action<object,object>>(() => {
            PropertyInfo prop = objType.GetProperty(name);
            if(prop==null){
                return (s,v) => {};
            }
            ParameterExpression pobj = 
                Expression.Parameter(typeof(object));
            ParameterExpression pval = 
                Expression.Parameter(typeof(object));
            Expression left = Expression.Property(
                Expression.TypeAs( pobj, objType), prop);
            Expression right = Expression.Convert(pval, prop.PropertyType);

            return Expression
            .Lambda<Action<object, object>>(
                Expression.Assign(left,right), pobj, pval).Compile();
        })).Value;

    f(obj,value);
}

用法....

SetProperty(parcelToInsert, c.ColumnName, dr[c.ColumnName])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM