加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

反射 – 如何优化此方法

发布时间:2020-12-16 09:28:44 所属栏目:百科 来源:网络整理
导读:private static void ConvertToUpper(object entity,Hashtable visited) { if (entity != null !visited.ContainsKey(entity)) { visited.Add(entity,entity); foreach (PropertyInfo propertyInfo in entity.GetType().GetProperties()) { if (!propertyInf
private static void ConvertToUpper(object entity,Hashtable visited)
    {
        if (entity != null && !visited.ContainsKey(entity))
        {
            visited.Add(entity,entity);

            foreach (PropertyInfo propertyInfo in entity.GetType().GetProperties())
            {
                if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
                    continue;

                object propertyValue = propertyInfo.GetValue(entity,null);

                Type propertyType;
                if ((propertyType = propertyInfo.PropertyType) == typeof(string))
                {
                    if (propertyValue != null && !propertyInfo.Name.Contains("password"))
                    {
                        propertyInfo.SetValue(entity,((string)propertyValue).ToUpper(),null);
                    }
                    continue;
                }

                if (!propertyType.IsValueType)
                {
                    IEnumerable enumerable;
                    if ((enumerable = propertyValue as IEnumerable) != null)
                    {
                        foreach (object value in enumerable)
                        {
                            ConvertToUpper(value,visited);
                        }
                    }
                    else
                    {
                        ConvertToUpper(propertyValue,visited);
                    }
                }
            }
        }
    }

现在它适用于列表相对较小的对象,但是一旦对象列表变大,就需要永远.我将如何优化它并设置最大深度的限制.

谢谢你的帮助

解决方法

我没有描述下面的代码,但它必须在复杂的结构上非常高效.

1)使用动态代码生成.

2)为生成的动态委托使用基于类型的缓存.

public class VisitorManager : HashSet<object>
{
  delegate void Visitor(VisitorManager manager,object entity);

  Dictionary<Type,Visitor> _visitors = new Dictionary<Type,Visitor>();

  void ConvertToUpperEnum(IEnumerable entity)
  {
    // TODO: this can be parallelized,but then we should thread-safe lock the cache 
    foreach (var obj in entity)
      ConvertToUpper(obj);
  }

  public void ConvertToUpper(object entity)
  {
    if (entity != null && !Contains(entity))
    {
      Add(entity);

      var visitor = GetCachedVisitor(entity.GetType());

      if (visitor != null)
        visitor(this,entity);
    }
  }

  Type _lastType;
  Visitor _lastVisitor;

  Visitor GetCachedVisitor(Type type)
  {
    if (type == _lastType)
      return _lastVisitor;

    _lastType = type;

    return _lastVisitor = GetVisitor(type);
  }

  Visitor GetVisitor(Type type)
  {
    Visitor result;

    if (!_visitors.TryGetValue(type,out result))
      _visitors[type] = result = BuildVisitor(type);

    return result;
  }

  static MethodInfo _toUpper = typeof(string).GetMethod("ToUpper",new Type[0]);
  static MethodInfo _convertToUpper = typeof(VisitorManager).GetMethod("ConvertToUpper",BindingFlags.Instance | BindingFlags.Public);
  static MethodInfo _convertToUpperEnum = typeof(VisitorManager).GetMethod("ConvertToUpperEnum",BindingFlags.Instance | BindingFlags.NonPublic);

  Visitor BuildVisitor(Type type)
  {
    var visitorManager = Expression.Parameter(typeof(VisitorManager),"manager");
    var entityParam = Expression.Parameter(typeof(object),"entity");

    var entityVar = Expression.Variable(type,"e");
    var cast = Expression.Assign(entityVar,Expression.Convert(entityParam,type));  // T e = (T)entity;

    var statements = new List<Expression>() { cast };

    foreach (var prop in type.GetProperties())
    {
      // if cannot read or cannot write - ignore property
      if (!prop.CanRead || !prop.CanWrite) continue;

      var propType = prop.PropertyType;

      // if property is value type - ignore property
      if (propType.IsValueType) continue;

      var isString = propType == typeof(string);

      // if string type but no password in property name - ignore property
      if (isString && !prop.Name.Contains("password"))
        continue;

      #region e.Prop

      var propAccess = Expression.Property(entityVar,prop); // e.Prop

      #endregion

      #region T value = e.Prop

      var value = Expression.Variable(propType,"value");
      var assignValue = Expression.Assign(value,propAccess);

      #endregion

      if (isString)
      {
        #region if (value != null) e.Prop = value.ToUpper();

        var ifThen = Expression.IfThen(Expression.NotEqual(value,Expression.Constant(null,typeof(string))),Expression.Assign(propAccess,Expression.Call(value,_toUpper)));

        #endregion

        statements.Add(Expression.Block(new[] { value },assignValue,ifThen));
      }
      else
      {
        #region var i = value as IEnumerable;

        var enumerable = Expression.Variable(typeof(IEnumerable),"i");

        var assignEnum = Expression.Assign(enumerable,Expression.TypeAs(value,enumerable.Type));

        #endregion

        #region if (i != null) manager.ConvertToUpperEnum(i); else manager.ConvertToUpper(value);

        var ifThenElse = Expression.IfThenElse(Expression.NotEqual(enumerable,Expression.Constant(null)),Expression.Call(visitorManager,_convertToUpperEnum,enumerable),_convertToUpper,value));

        #endregion

        statements.Add(Expression.Block(new[] { value,enumerable },assignEnum,ifThenElse));
      }
    }

    // no blocks 
    if (statements.Count <= 1)
      return null;

    return Expression.Lambda<Visitor>(Expression.Block(new[] { entityVar },statements),visitorManager,entityParam).Compile();
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读