Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I didn't profile the following code, but it must be very performant on complex structures.</p> <p>1) Uses dynamic code generation.</p> <p>2) Uses type-based cache for generated dynamic delegates.</p> <pre><code>public class VisitorManager : HashSet&lt;object&gt; { delegate void Visitor(VisitorManager manager, object entity); Dictionary&lt;Type, Visitor&gt; _visitors = new Dictionary&lt;Type, Visitor&gt;(); 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 &amp;&amp; !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&lt;Expression&gt;() { 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 &amp;&amp; !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), Expression.Call(visitorManager, _convertToUpper, value)); #endregion statements.Add(Expression.Block(new[] { value, enumerable }, assignValue, assignEnum, ifThenElse)); } } // no blocks if (statements.Count &lt;= 1) return null; return Expression.Lambda&lt;Visitor&gt;(Expression.Block(new[] { entityVar }, statements), visitorManager, entityParam).Compile(); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload