ようやく問題の根底に達し、私の最善の解決策は何なのかと思っています。つまり、ReflectiveReader
シリアル化されているオブジェクトにジェネリック型のインスタンスが格納されていなくても、XNA がジェネリック型パラメーターに反映されるという問題があります。
例がこれを最もよく示しています。次のモデルクラスを検討してください。
namespace Model
{
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
public abstract class Entity
{
}
public sealed class TestEntity : Entity
{
public Texture2D Texture
{
get;
set;
}
}
public abstract class EntityData
{
}
public abstract class EntityData<TData, TEntity> : EntityData
where TData : EntityData
where TEntity : Entity
{
}
public sealed class TestEntityData : EntityData<TestEntityData, TestEntity>
{
}
public sealed class LevelData
{
public List<EntityData> Entities
{
get;
set;
}
}
}
次に、後でContentManager
(Test.xml)を使用してロードするために、XMLファイル内にLevelDataのインスタンスを定義するとします。
<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Model="Model">
<Asset Type="Model:LevelData">
<Entities>
<Item Type="Model:TestEntityData">
</Item>
</Entities>
</Asset>
</XnaContent>
次に、この単純なロードロジックを考えます。
Content.Load<LevelData>("Test");
Content.Load<Texture2D>("Texture");
最初の行は成功しますが、2番目の行は例外をスローします。
Microsoft.Xna.Framework.Content.ContentLoadException was unhandled
Message=Error loading "Texture". ContentTypeReader Microsoft.Xna.Framework.Content.Texture2DReader, Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553 conflicts with existing handler Microsoft.Xna.Framework.Content.ReflectiveReader`1[[Microsoft.Xna.Framework.Graphics.Texture2D, Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553]], Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553 for type Microsoft.Xna.Framework.Graphics.Texture2D.
Source=Microsoft.Xna.Framework
StackTrace:
at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.AddTypeReader(String readerTypeName, ContentReader contentReader, ContentTypeReader reader)
at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(String readerTypeName, ContentReader contentReader, List`1& newTypeReaders)
at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.ReadTypeManifest(Int32 typeCount, ContentReader contentReader)
at Microsoft.Xna.Framework.Content.ContentReader.ReadHeader()
at Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]()
at Microsoft.Xna.Framework.Content.ContentManager.ReadAsset[T](String assetName, Action`1 recordDisposableObject)
at Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName)
at XnaContentManagerRepro.Game1.LoadContent() in D:\Temp\XnaContentManagerRepro\XnaContentManagerRepro\XnaContentManagerRepro\Game1.cs:line 53
at Microsoft.Xna.Framework.Game.Initialize()
at XnaContentManagerRepro.Game1.Initialize() in D:\Temp\XnaContentManagerRepro\XnaContentManagerRepro\XnaContentManagerRepro\Game1.cs:line 39
at Microsoft.Xna.Framework.Game.RunGame(Boolean useBlockingRun)
at Microsoft.Xna.Framework.Game.Run()
at XnaContentManagerRepro.Program.Main(String[] args) in D:\Temp\XnaContentManagerRepro\XnaContentManagerRepro\XnaContentManagerRepro\Program.cs:line 15
InnerException:
テクスチャをロードする行にブレークポイントを設定してからContentTypeReaderManager.nameToReader
メンバーを調べると、次のようになります。
ご覧のとおり、a ReflectiveReader
は実際にTexture2D
型にマップされています。これは私のTestEntity
クラスに由来します(上の画像で強調表示されているものの上のエントリを参照してください)。しかし、私のモデルクラスを調べると、ハングアップしLevelData
ているインスタンスがTestEntity
、そのEntity
中に、またはその中にさえありません。
TestEntityData
クラスをこれに変更すると:
public sealed class TestEntityData : EntityData<TestEntityData, Entity>
{
}
例外は発生しなくなりました。これTestEntity
は考慮されないため、どちらも考慮されませんTexture2D
。したがって、はReflectiveReader
私のモデルクラスのジェネリック型パラメーターを調べており、それに続いています。私はこれがバグであるとしか想定できません-なぜこれが必要になるのか私にはまったく意味がありません。
私のモデルクラスには、これらのジェネリック型パラメーターがあるのには十分な理由があります。これにより、モデルコードがはるかに単純になります。私はここで行き詰まっていますか?モデルをリファクタリングしてエンティティタイプのジェネリックタイプパラメータを持たないようにする唯一のオプションはありますか?私はの使用を検討しましたContentSerializerIgnoreAttribute
が、それはプロパティとフィールドに対してのみ機能するため、シリアル化に影響を与える必要があるのはそれらだけであることを考えると理にかなっています。
誰かアドバイスはありますか?
Load<Texture2D>
反射型リーダーが最初にそこにいなくて、テクスチャをロードする責任があると主張した場合、呼び出しは機能します。たとえば、テストレベルを読み込むための呼び出しをスキップすると、XNA TextureReader
または呼び出されたものを使用してテクスチャが正常に読み込まれます。汎用パラメーターがシリアル化に何らかの影響を与えることに異議を唱えます。シリアル化はオブジェクトの状態のみに関係し、問題のオブジェクトにはエンティティがありません。ジェネリックパラメーターは、データではなく、オブジェクトのメソッドでのみ使用されます。
Type.GetGenericArguments
、閉じたジェネリック型かオープンなジェネリック型かにかかわらず、を介して取得できます。おそらくドキュメントは間違っていて、あなたは正しいのですが、ドキュメントは、Texture2DがReflectionシステムでカバーされているため、シリアル化コードに表示される理由を説明しています。ここで誰もより良いアイデアを持っているようには見えないので、MSDNで質問することもできます。
Load<Texture2D>
、例外を発生させずに成功するにはどうすればよいですか?あなたの質問はかなり明確ですが、あなたの例がそれとどのように関連しているかは明確ではありません。ただし、シリアル化ではジェネリック型を確認する必要があると言います。そうしないと、ストリームから読み取ったものを再構築できることが保証されないためです。