コード例 #1
0
        public static void Make(ISymbol member, ITypeSymbol type, CodeWriter code, string name,
                                Location location, ScopeTracker scope = null)
        {
            var disposable = scope = scope == null?code.Encapsulate() : scope.Reference();

            using (disposable)
            {
                var nullable      = type.NullableAnnotation == NullableAnnotation.Annotated;
                var hasUnderlying = false;

                if (nullable)
                {
                    var underlying = GenerationEngine.GetNamedTypeSymbol(type).TypeArguments.FirstOrDefault();

                    hasUnderlying = underlying != null;
                    type          = underlying ?? type.WithNullableAnnotation(NullableAnnotation.None);

                    var check = hasUnderlying ? ".HasValue" : " is not null";

                    code.AppendLine($"writer.Write({name}{check});");
                    code.AppendLine($"if ({name}{check})");
                    code.Open();
                }

                name = nullable && hasUnderlying ? $"{name}.Value" : name;

                if (GenerationEngine.DefaultSerialization.TryGetValue(GenerationEngine.GetQualifiedName(type), out var serialization))
                {
                    serialization.Serialize(member, type, code, name, GenerationEngine.GetIdentifierWithArguments(type),
                                            location);

                    return;
                }

                if (GenerationEngine.IsPrimitive(type))
                {
                    if (!type.IsValueType)
                    {
                        using (code.BeginScope($"if ({name} is default({GenerationEngine.GetIdentifierWithArguments(type)}))"))
                        {
                            code.AppendLine(
                                $"throw new Exception(\"Member '{name}' is a primitive and has no value (null). If this is not an issue, please declare it as nullable.\");");
                        }
                    }

                    code.AppendLine($"writer.Write({name});");
                }
                else
                {
                    if (type.TypeKind != TypeKind.Struct && type.TypeKind != TypeKind.Enum && !nullable)
                    {
                        code.AppendLine($"writer.Write({name} is not null);");
                        code.AppendLine($"if ({name} is not null)");
                        code.Open();
                    }

                    switch (type.TypeKind)
                    {
                    case TypeKind.Enum:
                        code.AppendLine($"writer.Write((int) {name});");

                        break;

                    case TypeKind.Interface:
                    case TypeKind.Struct:
                    case TypeKind.Class:
                        var enumerable = GenerationEngine.GetQualifiedName(type) == GenerationEngine.EnumerableQualifiedName
                                ? GenerationEngine.GetNamedTypeSymbol(type)
                                : type.AllInterfaces.FirstOrDefault(self =>
                                                                    GenerationEngine.GetQualifiedName(self) == GenerationEngine.EnumerableQualifiedName);

                        if (enumerable != null)
                        {
                            var elementType = enumerable.TypeArguments.First();

                            using (code.BeginScope())
                            {
                                var countTechnique = GenerationEngine.GetAllMembers(type)
                                                     .Where(self => self is IPropertySymbol)
                                                     .Aggregate("Count()", (current, symbol) => symbol.Name switch
                                {
                                    "Count" => "Count",
                                    "Length" => "Length",
                                    _ => current
                                });

                                var prefix = GenerationEngine.GetVariableName(name);

                                code.AppendLine($"var {prefix}Count = {name}.{countTechnique};");
                                code.AppendLine($"writer.Write({prefix}Count);");

                                using (code.BeginScope($"foreach (var {prefix}Entry in {name})"))
                                {
                                    Make(member, elementType, code, $"{prefix}Entry", location,
                                         scope);
                                }
                            }
                        }