Beispiel #1
0
    internal Class CreateSerializerFor(TypeNode type) {
      // todo: look in the genCache for other serializer assemblies that may have already
      // created the serializer for this type and make an assembly reference to that 
      // serializer instead of creating a complete duplicate.
      TypeNode saved = tempChecker.currentType;

      Class c = (Class)serializers[type];
      if (c != null) return c;
      c = new Class();      
      c.Flags = TypeFlags.Class | TypeFlags.BeforeFieldInit;
      // copy the accessibility of the type we are serializing.
      c.Flags |= (type.Flags & (TypeFlags.Public | TypeFlags.NestedAssembly));
      c.Name = Identifier.For(GetSerializerName(type));
      c.Namespace = Identifier.For(GetSerializerNamespace(type));
      c.DeclaringModule = this.module;
      c.Members = new MemberList();
      c.Attributes = new AttributeList();
      c.BaseClass = Runtime.XmlSerializer;
      tempChecker.currentType = c;

      InstanceInitializer ii = Runtime.XmlSerializerAttribute.GetConstructor();
      MemberBinding mb = new MemberBinding(null, ii);
      mb.Type = Runtime.XmlSerializerAttribute;
      c.Attributes.Add(new AttributeNode(mb, null));
      if (cunit != null) {
        cunit.Namespaces[0].Types.Add(c);
      }
      this.module.Types.Add(c);

      Identifier typeId = Identifier.For("type"); // what we are writing to.
      Identifier rootName = Identifier.For("rootName"); // what we are writing to.
      Identifier rootNamespace = Identifier.For("rootNamespace"); // what we are writing to.

      // Constructor
      Method constructor = new InstanceInitializer();
      constructor.Name = StandardIds.Ctor;
      constructor.DeclaringType = c;
      constructor.Flags = MethodFlags.Public|MethodFlags.HideBySig|MethodFlags.SpecialName|MethodFlags.RTSpecialName;
      constructor.Parameters = new ParameterList();
      constructor.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, typeId, SystemTypes.Type, null, null));
      constructor.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, rootName, SystemTypes.String, null, null));
      constructor.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, rootNamespace, SystemTypes.String, null, null));
      constructor.ReturnType = SystemTypes.Void;
      c.Members.Add(constructor);

      // pass args thru to base XmlSerializer constructor.
      Block b = constructor.Body = new Block(new StatementList());
      b.Statements.Add(new ExpressionStatement(new MethodCall(new QualifiedIdentifier(new Base(), StandardIds.Ctor), 
        new ExpressionList(typeId, rootName, rootNamespace), NodeType.Call)));      
      //AddConsoleWrite(b.Statements, new Literal("Hello!!",SystemTypes.String));

      // Serialize(T source, XmlSerializationWriter writer) method
      Identifier src = Identifier.For("source"); // object being serialized.
      Identifier writer = Identifier.For("writer"); // what we are writing to.

      Method serialize = new Method();
      serialize.Name = Identifier.For("Serialize");        
      serialize.DeclaringType = c;
      serialize.Flags = MethodFlags.Public|MethodFlags.Static|MethodFlags.HideBySig;
      serialize.Parameters = new ParameterList();
      serialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, src, type, null, null));
      serialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, writer, Runtime.XmlSerializationWriter, null, null));
      serialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, rootName, SystemTypes.String, null, null));
      serialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, rootNamespace, SystemTypes.String, null, null));
      serialize.ReturnType = SystemTypes.Void;
      c.Members.Add(serialize);

      // T Deserialize(XmlReader reader, bool required, out bool result) method
      Identifier reader = Identifier.For("reader"); // what we are reading from.
      Identifier required = Identifier.For("required"); // whether an object is required or not.
      Identifier result = Identifier.For("result"); // whether we found anything.

      Method deserialize = new Method();
      deserialize.Name = Identifier.For("Deserialize");        
      deserialize.DeclaringType = c;
      deserialize.Flags = MethodFlags.Public|MethodFlags.Static|MethodFlags.HideBySig;
      deserialize.Parameters = new ParameterList();
      deserialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, reader, Runtime.XmlSerializationReader, null, null));
      deserialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.In, required, SystemTypes.Boolean, null, null));
      deserialize.Parameters.Add(new Parameter(new AttributeList(), ParameterFlags.Out, result, SystemTypes.Boolean.GetReferenceType(), null, null));
      deserialize.ReturnType = type;
      c.Members.Add(deserialize);

      // It is important that we add the serializer to the cache AFTER we create the methods, but 
      // BEFORE we create the method bodies so that we can handle recurrsive calls to AddCallSerializer which
      // happens in recurrsive structures like "class Foo { public Foo f; }".  Otherwise we'd get stuck in an
      // infinite loop.
      serializers[type] = c;

      // Body of serialize method.
      b = serialize.Body = new Block(new StatementList());
      StatementList statements = b.Statements;
      
      if (!AddWriteSimpleType(type, statements, c, writer, src, rootName, rootNamespace)) {
        MethodCall call = new MethodCall();
        call.Callee = new QualifiedIdentifier(writer,Identifier.For("WriteStartElement"));
        call.Operands = new ExpressionList();
        call.Operands.Add(rootName);
        call.Operands.Add(rootNamespace);
        statements.Add(new If(new BinaryExpression(rootName,Literal.Null,NodeType.Ne),
          new Block(new StatementList(new ExpressionStatement(call))),null));

        Expression source = src;

        if (type.Template == SystemTypes.GenericBoxed) {
          statements = AddCheckForNull(statements, Duplicate(src, c), type);
          type = Checker.GetCollectionElementType(type); 
          source = CastTo(src, type);//unbox it
        }

        if (type is TupleType) {
          AddWriteTuple(type as TupleType, statements, c, source, writer);
        } else if (type is TypeUnion) {
          AddWriteChoice(type as TypeUnion, statements, c, source, writer);
        } else if (IsStream(type)) {
          AddWriteStream(type, statements, c, source, writer);
        } else {
          SchemaElementDecl sd = SchemaElementDecl.Compile(this.module, type, Checker.GetCollectionElementType(type), this.errorHandler, schemaElementDeclCache);
          SchemaValidator validator = validator = sd.CreateValidator(this.errorHandler);      
          statements = AddCheckForNull(statements, Duplicate(src, c), type);
          AddWriteAttributes(statements, c, writer, source, validator);
          AddWriteContent(type, statements, c, writer, source, validator);        
        }
        call = new MethodCall();
        call.Callee = new QualifiedIdentifier(writer,Identifier.For("WriteEndElement"));
        call.Operands = new ExpressionList();
        statements.Add(new If(new BinaryExpression(rootName,Literal.Null,NodeType.Ne),
          new Block(new StatementList(new ExpressionStatement(call))),null));
      }
      // body of deserialize method.
      b = deserialize.Body = new Block(new StatementList());
      statements = b.Statements;

      Local target = new Local(Identifier.Empty, type);

      if (type.Template == SystemTypes.GenericBoxed){
        type = Checker.GetCollectionElementType(type);
      }

      if (type is TupleType) {
        AddReadTuple(b, type as TupleType, statements, reader, target, required, result);
      } else if (type is TypeUnion) {
        AddReadChoice(b, type as TypeUnion, statements, reader, target, required, result);
      } else if (IsStream(type)) {
        AddReadStream(b, type, statements, reader, target, result);
      } else {
        if (type is TypeAlias) {
          type = ((TypeAlias)type).AliasedType;
        }

        // Then we are already positioned on the element to be deserialized. 
        statements.Add(new AssignmentStatement(required, Literal.True));
        if (!AddReadSimpleType(type, statements, reader, target, result, false)) {
          if (!type.IsValueType && !type.IsAbstract && type.GetConstructor() != null) {
            Construct cons = new Construct(new MemberBinding(null, type), new ExpressionList(), type);
            statements.Add(new AssignmentStatement(target, cons));
          }
          SchemaElementDecl sd = SchemaElementDecl.Compile(this.module, type, Checker.GetCollectionElementType(type), this.errorHandler, schemaElementDeclCache);
          SchemaValidator validator = validator = sd.CreateValidator(this.errorHandler);      
          AddReadAttributes(type, statements, reader, target, validator);
          AddReadContent(c, b, type, statements, reader, target, required, result, validator);
        }
      }
      statements.Add(new Return(target));
      tempChecker.currentType = saved;
      return c;
    }