Пример #1
0
        public static Func <T, int, string> GenerateToString <T>()
        {
            var param  = Expression.Parameter(typeof(T), "obj");
            var indent = Expression.Parameter(typeof(int), "indentation");
            var array  = Expression.Parameter(typeof(string[]), "array");

            var stringConcat2 =
                typeof(string).GetMethod("Concat", new Type[] {
                typeof(object),
                typeof(object)
            });

            var stringConcat3 =
                typeof(string).GetMethod("Concat", new Type[] {
                typeof(object),
                typeof(object),
                typeof(object)
            });

            var stringJoin =
                typeof(string).GetMethod("Join", new[] { typeof(string), typeof(string[]) });

            var lineIndent = ((Func <int, string>)IlHelpers.GetRecordLineIndent).Method;

            var getStrings =
                GetFields <T>()
                .Select((fieldInfo, i) =>
                        // String concat
                        StringConcat2(
                            // "Name: "
                            Expression.Constant(getFieldName(fieldInfo) + ": ", typeof(string)),
                            // And the to string result
                            getToStringCall(fieldInfo)
                            ));

            var block = Expression.Block(
                new[] { array },
                Expression.Assign(array, Expression.NewArrayInit(typeof(string), getStrings)),
                Expression.Call(
                    stringConcat3,
                    StringConcat2(
                        Expression.Constant("{\n"),
                        Expression.Call(lineIndent, indent)
                        ),
                    Expression.Call(
                        stringJoin,
                        StringConcat2(
                            Expression.Constant(",\n"),
                            Expression.Call(lineIndent, indent)),
                        array),
                    StringConcat3(
                        Expression.Constant("\n"),
                        Expression.Call(lineIndent, Expression.Subtract(indent, Expression.Constant(1, typeof(int)))),
                        Expression.Constant("}", typeof(string))
                        )
                    ));


            return(Expression.Lambda <Func <T, int, string> >(block, param, indent).Compile());

            /***** Nested methods *****/

            string getFieldName(FieldInfo nfo)
            {
                if (nfo.CustomAttributes.Any(x => x.AttributeType == typeof(CompilerGeneratedAttribute)))
                {
                    return(IlHelpers.StripBakingFieldName(nfo.Name));
                }

                return(nfo.Name);
            }

            Expression getToStringCall(FieldInfo nfo)
            {
                var prettyToString = typeof(object).GetMethod("ToString", new[] { typeof(int) });

                if (prettyToString != null)
                {
                    return(Expression.Call(
                               Expression.Field(param, nfo),
                               prettyToString,
                               Expression.Add(indent, Expression.Constant(1))));
                }

                return(Expression.Call(
                           Expression.Field(param, nfo),
                           typeof(object).GetMethod("ToString", new Type[] { })));
            }

            Expression StringConcat2(Expression a, Expression b)
            {
                return(Expression.Call(
                           stringConcat2,
                           a,
                           b));
            }

            Expression StringConcat3(Expression a, Expression b, Expression c)
            {
                return(Expression.Call(
                           stringConcat3,
                           a,
                           b,
                           c));
            }
        }
Пример #2
0
        internal static IReadOnlyDictionary <MemberInfo, Action <T, object> > GenerateRecordFieldsSetMap <T>()
        {
            var(props, allFields) =
                GetMembers <T>()
                .Where(x => x.MemberType == MemberTypes.Field || x.MemberType == MemberTypes.Property)
                .Partition(x => x.MemberType == MemberTypes.Property)
                .Do(x => (
                        x.trues.Cast <PropertyInfo>().ToArray(),
                        x.falses.Cast <FieldInfo>().ToArray()));

            var(autoFields, realFields) =
                allFields
                .Partition(x => x.CustomAttributes.Any(y => y.AttributeType == typeof(CompilerGeneratedAttribute)))
                .Do(x => (x.trues.ToArray(), x.falses.ToArray()));

            var autoProps =
                autoFields
                .Join(
                    props,
                    x => IlHelpers.StripBakingFieldName(x.Name),
                    x => x.Name,
                    (x, y) => (prop: y, field: x))
                .ToArray();

            var realProps =
                props
                .Except(autoProps.Select(x => x.prop))
                .Where(x => x.CanWrite)
                .ToArray();

            var value  = Expression.Parameter(typeof(object), "value");
            var target = Expression.Parameter(typeof(T), "target");

            var realFieldAssignments =
                realFields
                .Select(x =>
                        (member: (MemberInfo)x,
                         expression: (Expression)MakeFieldAssign(target, value, x)));

            var autoPropsAssignments =
                autoProps
                .Select(x =>
                        (member: (MemberInfo)x.prop,
                         expression: (Expression)MakeFieldAssign(target, value, x.field)));

            var realPropsAssignments =
                realProps
                .Select(x =>
                        (member: (MemberInfo)x,
                         expression: (Expression)Expression.Assign(
                             Expression.Property(target, x.SetMethod),
                             value)));

            return
                (realFieldAssignments
                 .Union(autoPropsAssignments)
                 .Union(realPropsAssignments)
                 .ToDictionary(
                     x => x.member,
                     x => Expression.Lambda <Action <T, object> >(x.expression, target, value).Compile()));
        }