XNA Creators Club Online
Page 1 of 1 (7 items)
Sort Posts: Previous Next

InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

Last post 10/22/2009 5:11 PM by jwatte. 6 replies.
  • 10/20/2009 3:26 AM

    InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    And now I'm getting an InvalidOperationException inside Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase.ValidateSkippedMember.
    This is on a member that is marked as [ContentSerializer(SharedResource=true)]

    My guess is that this is because I have an array of the guys, and while the array can be marked shared, the objects within the array cannot.

    Here's most of the relevant code:

    namespace YarBase 
      public class LevelData<EffectType, VertexBufferType, VertexDeclarationType> 
        where EffectType : class 
        where VertexBufferType : class 
        where VertexDeclarationType : class 
      { 
        public LevelGeometry<EffectType, VertexBufferType, VertexDeclarationType> Geometry { getset; } 
        public Dictionary<TileAddress, Tile> Tiles { getset; } 
      } 
     
      public class LevelGeometry<EffectType, VertexBufferType, VertexDeclarationType> 
        where EffectType : class 
        where VertexBufferType : class 
        where VertexDeclarationType : class 
      { 
        [ContentSerializer(SharedResource = true)] 
        public EffectType[] Effects { getset; } 
        public VertexBufferType VertexBuffer { getset; } 
        public VertexDeclarationType VertexDeclaration { getset; } 
        public IndexRange<EffectType>[] Ranges { getset; } 
      } 
     
      public struct IndexRange<EffectType> 
        where EffectType : class 
      { 
        [ContentSerializer(SharedResource = true)] 
        public EffectType effect; 
        public int fromVertex; 
        public int numTriangles; 
        public Vector3 MinBounds; 
        public Vector3 MaxBounds; 
      } 
       
     


    EffectType is EffectMaterialContentIndirect in the content pipeline (which has a custom type writer) and EffectIndirect at runtime (which has a custom type reader). All they do is delegate to WriteObject<EffectMaterialContent> and ReadObject<Effect>, respectively. (ReadObject<Effect> to get around the problem that, internally, it uses the private EffectMaterial class).


    {"Unable to serialize member effect of YarBase.IndexRange`1[KiloWatt.Pipeline.EffectMaterialContentIndirect]."}

       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.ValidateSkippedMember(MemberInfo memberInfo)
       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.TryInitialize(TSerializer serializer, Type declaringType, FieldInfo fieldInfo)
       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.CreateMemberHelpers[TDerived](TSerializer serializer, Type declaringType, List`1 memberHelpers)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriter.Initialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentTypeWriter.DoInitialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.InitializeTypeWriter(ContentTypeWriter writer)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriterInternal(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriter(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ArrayWriter`1.Initialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentTypeWriter.DoInitialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.InitializeTypeWriter(ContentTypeWriter writer)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriterInternal(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriter(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriterMemberHelper.Initialize(ContentCompiler compiler, MemberInfo memberInfo, Type memberType)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriterMemberHelper.Initialize(ContentCompiler compiler, PropertyInfo propertyInfo)
       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.TryInitialize(TSerializer serializer, Type declaringType, PropertyInfo propertyInfo)
       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.CreateMemberHelpers[TDerived](TSerializer serializer, Type declaringType, List`1 memberHelpers)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriter.Initialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentTypeWriter.DoInitialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.InitializeTypeWriter(ContentTypeWriter writer)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriterInternal(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriter(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriterMemberHelper.Initialize(ContentCompiler compiler, MemberInfo memberInfo, Type memberType)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriterMemberHelper.Initialize(ContentCompiler compiler, PropertyInfo propertyInfo)
       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.TryInitialize(TSerializer serializer, Type declaringType, PropertyInfo propertyInfo)
       at Microsoft.Xna.Framework.Content.Pipeline.MemberHelperBase`1.CreateMemberHelpers[TDerived](TSerializer serializer, Type declaringType, List`1 memberHelpers)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ReflectiveWriter.Initialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentTypeWriter.DoInitialize(ContentCompiler compiler)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.InitializeTypeWriter(ContentTypeWriter writer)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.GetTypeWriterInternal(Type type)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentWriter.GetTypeWriter(Type type, Int32& typeIndex)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentWriter.WriteObject[T](T value)
       at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler.ContentCompiler.Compile(Stream output, Object value, TargetPlatform targetPlatform, Boolean compressContent, String rootDirectory, String referenceRelocationPath)
       at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.SerializeOutputAsset(BuildItem item, Object assetData, String outputFilename)
       at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.SerializeAsset(BuildItem item, Object assetData)
    
    
    
    
    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
  • 10/20/2009 4:00 PM In reply to

    Re: InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    I don't fully understand this problem, in fact I don't think I properly understand what you are trying to achieve here (it would be useful if I could see the EffectMaterialContentIndirect class) but regarding the shared resource thing, you're right that the attribute only applies to the field which holds the array, rather than the elements within that array. There's no way to control the serialization of collection elements using attributes. To serialize individual elements as shared resources, you need to make a new type.

    XNA Framework Developer - blog - homepage
  • 10/20/2009 4:28 PM In reply to

    Re: InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    What I'm trying to accomplish is using automatic serialization of a custom geometry class. However, various design decisions in the content pipeline classes (mostly having to do with not documenting, or making classes private) have made this exceedingly hard. It would have been faster to just write custom type readers/writers for my classes than using the automatic serialization at this point...

    The specific problem in this post is the following:

    I create a class. That class has a custom type writer. The custom type writer returns another class as the runtime type.

    I then have an array of instances of that class in one object that's being serialized using automatic serialization.

    I separately have another type instance that contains references to that same class, to instances which are within the array.

    I mark the reference in the second type as SharedResource.

    At this point, I get an exception when trying to serialize the data, presumably because the instances of the object are seen without SharedResource when serializing the array of references, and then seen with SharedResource in the later reference.

    Thus, the conclusion is that you cannot use the automatic serialization when you want to use arrays of shared object references. This is not documented anywhere, and caused me to lose some time last night. The diagnostic (exception) was also highly unhelpful.

    Btw:

    Another thing that caused me to lose time last night include the fact that EffectMaterial is a private class to the Content runtime assembly, so I cannot use the "generic type argument" work-around to use automatic serialization with content pipeline classes, as recommended in your blog.

    A third thing that caused me to lose time was the fact that there is no VertexDeclarationContent class -- instead, we're supposed to know that writing an array of VertexElement[] will be loaded back as a VertexDeclaration at runtime. That's something that's highly unintuitive, and not documented at all.

    Also, because I want the runtime types to be IDisposable, but the compile-time types are not, I have to do type testing within the container classes -- I can't just say "where blah : IDisposable" because then the type cannot be used at compile time. It would have been cleaner if the design type types are also disposable. Again, this is because I need to use the generic type parameter work-around to use content pipeline types with the automatic serializer.


    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
  • 10/20/2009 5:06 PM In reply to

    Re: InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    jwatte:
    At this point, I get an exception when trying to serialize the data, presumably because the instances of the object are seen without SharedResource when serializing the array of references, and then seen with SharedResource in the later reference.


    That actually ought to work. You'll just end up with two copies of the same object in the .xnb file, one from the shared resource, another from the place where the same object was serialized in non-shared mode. I have a feeling the exception might actually be caused by something else.

    jwatte:

    Thus, the conclusion is that you cannot use the automatic serialization when you want to use arrays of shared object references.


    Correct.

    At one point I considered adding another serializer control attribute to specify shared mode for elements inside a collection (the attribute would go on the collection parent field), but that never made it far enough up the priority list to actually get implemented.
    XNA Framework Developer - blog - homepage
  • 10/21/2009 8:31 PM In reply to

    Re: InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    Shawn Hargreaves:
    That actually ought to work. You'll just end up with two copies of the same object in the .xnb file, one from the shared resource, another from the place where the same object was serialized in non-shared mode. I have a feeling the exception might actually be caused by something else.


    From my testing, it was entirely dependent on whether I had the ContentSerializer(SharedResource) attribute on the individual reference or not.

    Btw: while you think it should "work," the fact that the shared resource isn't actually shared would pretty much hose the data structure I was using, and that bug would have been much harder to track down than a cryptic exception. I'm pretty glad it didn't "work" like that!
    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
  • 10/21/2009 9:09 PM In reply to

    Re: InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    I guess I was using "work" in the sense of "writes out some bytes without throwing an exception", rather than "actually does what you wanted it to"  :-)
    XNA Framework Developer - blog - homepage
  • 10/22/2009 5:11 PM In reply to

    Re: InvalidOperationException when using ContentSerializer(SharedResource=true) on objects found in arrays

    Just like software project "success" means "we put the system in production on the given date, over the objection of the entire support team"?
    Yeah, I'm not a big fan of that kind of "works" or "success" :-)

    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
Page 1 of 1 (7 items) Previous Next