Cuối cùng tôi đã đi đến tận cùng của một vấn đề và đang tự hỏi cách truy đòi tốt nhất của tôi là gì. Nói tóm lại, vấn đề là XNA ReflectiveReader
phản ánh thành các tham số loại chung, ngay cả khi không có trường hợp nào của loại chung đó được lưu trữ trong đối tượng được tuần tự hóa.
Một ví dụ tốt nhất chứng minh điều này. Hãy xem xét các lớp mô hình sau:
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;
}
}
}
Bây giờ, giả sử tôi muốn xác định một thể hiện của LevelData bên trong một tệp XML để được tải sau đó với ContentManager
( Test.xml ):
<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Model="Model">
<Asset Type="Model:LevelData">
<Entities>
<Item Type="Model:TestEntityData">
</Item>
</Entities>
</Asset>
</XnaContent>
Bây giờ hãy xem xét logic tải đơn giản này:
Content.Load<LevelData>("Test");
Content.Load<Texture2D>("Texture");
Dòng đầu tiên thành công, nhưng dòng thứ hai ném một ngoại lệ:
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:
Nếu tôi đặt một điểm dừng trên dòng tải kết cấu và sau đó kiểm tra ContentTypeReaderManager.nameToReader
thành viên, tôi thấy điều này:
Như bạn có thể thấy, a ReflectiveReader
thực sự đang được ánh xạ cho Texture2D
loại. Điều này xuất phát từ TestEntity
lớp của tôi (xem các mục bên trên một mục được tô sáng trong hình trên). Nhưng nếu bạn kiểm tra các lớp mô hình của tôi, không có gì tồn tại LevelData
có thể hiện TestEntity
hoặc thậm chí Entity
trong đó!
Nếu tôi thay đổi TestEntityData
lớp thành này:
public sealed class TestEntityData : EntityData<TestEntityData, Entity>
{
}
Ngoại lệ không còn xảy ra. Đó là bởi vì TestEntity
không bao giờ được xem xét, vì vậy cũng không Texture2D
. Vì vậy, việc ReflectiveReader
xem xét - và sau đây - các tham số loại chung trong các lớp mô hình của tôi! Tôi chỉ có thể cho rằng đây là một lỗi - nó không có ý nghĩa gì với tôi tại sao điều này lại cần thiết.
Các lớp mô hình của tôi có các tham số kiểu chung này vì một lý do chính đáng - chúng làm cho mã mô hình của tôi đơn giản hơn nhiều. Tôi có bị kẹt ở đây không? Là lựa chọn duy nhất của tôi để cấu trúc lại các mô hình của tôi để không bao giờ có tham số loại chung của các loại thực thể của tôi? Tôi đã cân nhắc sử dụng ContentSerializerIgnoreAttribute
, nhưng nó chỉ hoạt động chống lại các thuộc tính và các trường, điều này hợp lý khi xem chúng là những thứ duy nhất có ảnh hưởng đến việc xê-ri hóa.
Bất cứ ai có lời khuyên?
Load<Texture2D>
hoạt động nếu đầu đọc phản xạ chưa có trong đó trước và tuyên bố rằng nó có thể sửa chữa để tải kết cấu. Ví dụ, nếu tôi bỏ qua cuộc gọi để tải mức thử nghiệm của mình thì kết cấu sẽ tải thành công bằng cách sử dụng XNA TextureReader
hoặc bất cứ thứ gì nó được gọi. Tôi tranh luận rằng các tham số chung có bất kỳ liên quan đến tuần tự hóa. Tuần tự hóa chỉ liên quan đến trạng thái của một đối tượng và đối tượng được đề cập không có thực thể trong đó. Tham số chung chỉ được sử dụng trong các phương thức trên đối tượng, không phải trong dữ liệu.
Type.GetGenericArguments
, cho dù là loại chung đóng hay loại chung mở. Có thể các tài liệu sai và bạn đúng, nhưng các tài liệu giải thích tại sao Texture2D được bao phủ bởi hệ thống Reflection và do đó hiển thị trong mã tuần tự hóa của bạn. Có lẽ bạn có thể hỏi trên MSDN vì dường như không có ai ở đây có ý tưởng tốt hơn.
Load<Texture2D>
thành công mà không cần đưa ra một ngoại lệ? Câu hỏi của bạn khá rõ ràng nhưng không rõ ví dụ của bạn liên quan đến nó như thế nào. Tuy nhiên, tôi sẽ nói rằng việc xê-ri hóa phải xem xét các loại chung, bởi vì nếu không thì nó không thể được đảm bảo để có thể tái tạo lại bất cứ thứ gì nó đọc được từ luồng.