private Expression MakeNullableEnumLambda(Type underlyingType, Type nullableType)
        {
            var str = Expression.Parameter(typeof(string), "str");

            var isNullOrEmpty = Expression.Call(XmlSerializerMembers.String_IsNullOrEmpty, str);

            var @null = Expression.Constant(null, nullableType);
            var val   = GetEnumSwitch(str, underlyingType);
            var cast  = Expression.Convert(val, nullableType);

            var condition = Expression.Condition(
                isNullOrEmpty, //if (string.IsNullOrEmpty(str)
                @null,         //    return null;
                cast           //return ToEnum(str)
                );

            var lambda = Expression.Lambda(
                Expression.Block(
                    condition
                    ),
                $"ReadNullable{underlyingType.Name}",
                new[] { str, XmlExpressionConstants.Serializer }
                );

            return(XmlSerializerGenerator.LambdaOrDelegate(lambda));
        }
        private Expression MakeEnumLambda(Type type)
        {
            var p = Expression.Parameter(typeof(string), "s");

            var c = ReflectionCacheManager.GetEnumCache(type).Cache;

            var fields = c.Fields;

            List <SwitchCase> cases = new List <SwitchCase>();

            foreach (var f in fields)
            {
                if (f.Field.FieldType.IsEnum)
                {
                    var val = f.Field.GetValue(null);

                    var caseConditions = f.Attributes.Where(v => v.Key == typeof(XmlEnumAttribute) || v.Key == typeof(XmlEnumAlternateName))
                                         .SelectMany(a => a.Value).Cast <XmlEnumAttribute>().Select(a => Expression.Constant(a.Name)).ToArray();

                    if (caseConditions.Length > 0)
                    {
                        cases.Add(Expression.SwitchCase(Expression.Constant(val), caseConditions));
                    }
                }
            }

            var failEnum      = XmlExpressionConstants.FailEnum(p, type);
            var throwFailEnum = Expression.Throw(failEnum, type);

            Expression switchBody;

            if (cases.Count > 0)
            {
                switchBody = Expression.Switch(p, throwFailEnum, cases.ToArray());
            }
            else
            {
                switchBody = throwFailEnum;
            }

            var lambda = Expression.Lambda(
                Expression.Block(switchBody),
                $"Read{type.Name}",
                new[] { p, XmlExpressionConstants.Serializer });

            return(XmlSerializerGenerator.LambdaOrDelegate(lambda));
        }
        private Expression MakeNullableMethod(
            Func <Expression, MethodCallExpression> deserializeString,
            Func <Expression, MethodCallExpression> deserializeToConverter,
            Func <Expression, MethodCallExpression> deserializeFromConverter)
        {
            var parameter     = Expression.Parameter(typeof(string), "str");
            var isNullOrEmpty = Expression.Call(XmlSerializerMembers.String_IsNullOrEmpty, parameter);

            var assignment = parameter.Assign(XmlExpressionConstants.ToNullableString(parameter));

            var eval = ConvertValue(parameter, deserializeString, deserializeToConverter, deserializeFromConverter);

            var nullableType = eval.Type;

            //Generally speaking, eval.Type is not the nullable type. It's only nullable
            //when a special deserializeFromConverter method has been specified (such as in the case of
            //nullable DateTime)
            if (Nullable.GetUnderlyingType(nullableType) == null)
            {
                nullableType = typeof(Nullable <>).MakeGenericType(eval.Type);
            }

            var condition = Expression.Condition(
                isNullOrEmpty, //string.IsNullOrEmpty(str)
                Expression.Constant(null, nullableType),
                Expression.Convert(eval, nullableType)
                );

            var name = $"ToNullable{eval.Type.Name}";

            if (valueConverter != null)
            {
                name += "_With" + converterType.Name;
            }

            var lambda = Expression.Lambda(
                Expression.Block(condition),
                name,
                new[] { parameter, XmlExpressionConstants.Serializer }
                );

            return(XmlSerializerGenerator.LambdaOrDelegate(lambda));
        }