Tại sao Trình quản lý nội dung của XNA tuân theo các tham số loại chung cho mục đích tuần tự hóa?


8

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 ReflectiveReaderphả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.nameToReaderthành viên, tôi thấy điều này:

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy, a ReflectiveReaderthực sự đang được ánh xạ cho Texture2Dloại. Điều này xuất phát từ TestEntitylớ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 LevelDatacó thể hiện TestEntityhoặc thậm chí Entitytrong đó!

Nếu tôi thay đổi TestEntityDatalớ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ì TestEntitykhông bao giờ được xem xét, vì vậy cũng không Texture2D. Vì vậy, việc ReflectiveReaderxem 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?


Tôi không quen thuộc với XNA, nhưng nếu bạn loại bỏ Texture2D khỏi xem xét, làm thế nào có thể 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.
Kylotan

Gọi 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 TextureReaderhoặ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.
tôi--

@ user13414, tuần tự hóa cần biết chính xác loại đối tượng nào để tạo lại nó ở đầu kia - ví dụ, sẽ có các hàm tạo để gọi. Và loại đối tượng bao gồm đối số cụ thể được truyền dưới dạng tham số chung, ít nhất là trong các ngôn ngữ như C # và C ++ (có thể không có trong Java, trong đó thực hiện các khái quát khác nhau một chút).
Kylotan

@Kylotan: lớp cơ sở là chung, không phải lớp con (là đối tượng được tuần tự hóa). Nó là một loại chung chung, không phải là một loại mở.
tôi--

2
Các tài liệu tôi liên kết để nói rằng phản xạ .NET lưu trữ thông tin về các loại chung liên quan đến các tham số loại của chúng và điều này có thể được lấy thông qua 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.
Kylotan

Câu trả lời:


4

Mặc dù nói chung , việc xê-ri hóa không nhất thiết phải liên quan đến các loại đối tượng được đề cập và chỉ ghi lại các biểu diễn về trạng thái của chúng ... không phải tất cả các triển khai tuần tự hóa đều làm điều đó. Hầu hết các built-in .NET phương pháp serialization làm thông tin hồ sơ về các loại tham gia serialization. Có những lợi thế cho sự lựa chọn đó (cho phép xác nhận mạnh mẽ hơn) cũng như những nhược điểm (kích thước đối tượng được tuần tự hóa lớn hơn), nhưng điều đó không sai mỗi se và bạn chỉ cần sống với nó.

Đối với các loại nội dung của XNA, đối với các loại của bạn, đi qua biểu đồ thuộc tính (và trường) tuần tự hóa và tạo các trình đọc cho chúng. Bạn có thể thấy hành vi này nếu bạn kiểm tra khởi tạo cho ReflectiveReader<T>( Initializephương thức, không phải hàm tạo). Nó thực hiện điều này thông qua sự phản chiếu, không dựa trên dữ liệu thực tế trong XML (một lần nữa, điều này có thể kiểm chứng được bằng cách xem mã được phản ánh). Vì vậy, không có vấn đề gì nếu có tham chiếu đến kết cấu trong dữ liệu của bạn hay không, nếu có một Texture2Dthuộc tính trong biểu đồ thuộc tính của loại, nó sẽ cố gắng tạo một trình đọc cho nó như là một phần của việc khởi tạo đường ống nội dung.

Bạn không được phép sử dụng các tham chiếu trực tiếp đến Texture2Dcác đối tượng trong nội dung tùy chỉnh của mình. Bạn có thể tìm thấy chủ đề này (hoặc cái này , ở mức độ thấp hơn). Giải pháp bị cáo buộc cho vấn đề này là sử dụng các tài liệu tham khảo bên ngoài để Texture2DContentthay thế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.