public FieldHasher(PropertyInfo[] props, FieldHasherOptions options) { this.Props = props; this.expr = CreateExpression(props, options); }
private Func <T1, int> CreateExpression(PropertyInfo[] fields, FieldHasherOptions options) { /* * $hash = 17; * $hash += $hash * 23 + .Call ($obj.a).GetHashCode(); * $hash += $hash * 23 + .Call ($obj.b).GetHashCode(); * .If ($obj.s != null) { * $hash += $hash * 23 + .Call (.Call ($obj.s).Trim()).GetHashCode() * } .Else { * $hash *= 23 * }; * $hash += $hash * 23 + .Call ($obj.date).GetHashCode(); * $hash += $hash * 23 + .Call ($obj.mynullable).GetHashCode(); * $hash */ const int prim = 17; const int prim2 = 23; var t1param = EE.Param <T1>("obj"); var resultHash = EE.Param <int>("hash"); var ass = Expression.Assign(resultHash, Expression.Constant(prim)); var block = new List <Expression>(); block.Add(ass); var returnLabel = Expression.Label(typeof(int)); var whenNull = options.ZeroIfNulls ? Expression.Return(returnLabel, Expression.Constant(0)) : resultHash.MulAssign(prim2); block.AddRange(fields.Select(pi => { var dotted = t1param.Dot(pi.Name); var propType = pi.PropertyType; var addAssignHashCode = Expression.AddAssign(resultHash, resultHash.Mul(prim2).Add(dotted.Call("GetHashCode"))); // nullable if (options.ZeroIfNulls && Nullable.GetUnderlyingType(propType) != null) { return(Expression.IfThenElse( dotted.NotNull(), addAssignHashCode, whenNull)); } // value type but not nullabl if (propType.IsValueType) { return((Expression)addAssignHashCode); } // normalized string var normalized = propType == typeof(string) && options.StringNormalizer != null ? options.StringNormalizer(dotted) : dotted; var iffed = Expression.IfThenElse(dotted.NotNull(), Expression.AddAssign(resultHash, resultHash.Mul(prim2).Add(normalized.Call("GetHashCode"))), whenNull); return(iffed); })); block.Add(Expression.Label(returnLabel, resultHash)); var eblock = Expression.Block(new [] { resultHash }, block); var l = Expression.Lambda <Func <T1, int> >(eblock, t1param); return(l.Compile()); }