在从接口序列化泛型类时,如何让DataContractJsonSerializer在类型提示中使用具体类型 [英] How do I get DataContractJsonSerializer to use concrete type in type hint when serializing generic class from interface

查看:121
本文介绍了在从接口序列化泛型类时,如何让DataContractJsonSerializer在类型提示中使用具体类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一组类,如下所示:一个执行并存储结果的命令;
一个响应,它是为了以序列化的形式返回结果而创建的(加上我遗漏的额外的元数据)。 Response.Result 必须是类型的对象,因为它用于一堆不同的命令,每个命令都可以有任何类型的Result。



命令是通用的,我希望它接受一个接口而不是具体类型,但是当我这样做时,序列化响应包含以下类型提示:

__ type: ResultOfanyType:#serialization



而不是以下命令,它是在命令接受具体类型时生成的:

__ type:ResultOfMyObjectDhOQ6IBI:#serialization

我需要类型提示来包含具体类型而不是ResultOfanyType。为什么接口在这种情况下被区别对待?请注意,当Type是serialized Command的直接属性时,那么具体类型将包含在类型提示中。



我尝试更改输入的Result的Response属性结果,但没有效果。



这是代码。简单地取消注释/注释Main中创建命令的行,以及为替代版本列出的已知类型。

  using System; 
使用System.Collections.Generic;
使用System.IO;
使用System.Runtime.Serialization;
使用System.Runtime.Serialization.Json;

命名空间序列化
{
类程序
{
static void Main(string [] args)
{
响应响应= new Response();
response.ResponseStatus =ok;
ConcreteCommand命令=新建ConcreteCommand(); //用下面的行切换以测试接口
// InterfaceCommand命令= new InterfaceCommand();
command.Execute();
response.Results = command.Results;
列表<类型> knownTypes =新列表<类型>
{
typeof(Result< MyObject>),//用下面的接口行切换以测试接口
typeof(MyObject)
// typeof(Result< IMyObject>),
// typeof(IMyObject)
};
DataContractJsonSerializer serializer = new DataContractJsonSerializer(response.GetType(),knownTypes,int.MaxValue,false,null,true);
Stream stream = new MemoryStream();
serializer.WriteObject(stream,response);
stream.Position = 0;
StreamReader reader = new StreamReader(stream);
string output = reader.ReadToEnd();
Console.WriteLine(输出);
}
}

public interface IMyObject
{
string name {get;组; }
[DataContract]
[KnownType(typeof(MyObject))]
public class MyObject:IMyObject
{
[DataMember ]
公共字符串名称{get;组; }
}

[DataContract]
public class Result< T>
{
[DataMember]
public string Status {get;组; }

[DataMember]
public T Item {get;组; }
}

公共抽象类BaseCommand< T>
{
保护结果< T> results = new Result< T>();

protected T resultObject;

公共对象结果
{
get {return this.results; }
}

public T ResultObject
{
get {return this.resultObject; }
}

public abstract void Execute();
}

public class InterfaceCommand:BaseCommand< IMyObject>
{
public override void Execute()
{
IMyObject myobject = new MyObject();
myobject.name =我的对象;
结果< IMyObject> result = new Result< IMyObject>();
result.Item = myobject;
result.Status =ok;
this.results = result;
this.resultObject = myobject;
}
}

公共类ConcreteCommand:BaseCommand< MyObject>
{
public override void Execute()
{
MyObject myobject = new MyObject();
myobject.name =我的对象;
结果< MyObject> result = new Result< MyObject>();
result.Item = myobject;
result.Status =ok;
this.results = result;
this.resultObject = myobject;


$ b [DataContract]
public class Response
{
[DataMember]
public string ResponseStatus {get;组; }

[DataMember]
public object Results {get;组; }
}
}


解决方案

如何...

 类程序
{
static void Main(string [] args)
{
Response response = new Response();
response.ResponseStatus =ok;
// ConcreteCommand命令=新建ConcreteCommand(); //用下面的行切换以测试接口
InterfaceCommand命令= new InterfaceCommand();
command.Execute();
response.Results = command.Results;
列表<类型> knownTypes =新列表<类型>
{
typeof(MyObject),
typeof(Result< MyObject>)//用下面的行切换以测试接口
// typeof(Result< IMyObject>)
};
DataContractJsonSerializer serializer = new DataContractJsonSerializer(response.GetType(),knownTypes,int.MaxValue,false,null,true);
Stream stream = new MemoryStream();
serializer.WriteObject(stream,response);
stream.Position = 0;
StreamReader reader = new StreamReader(stream);
string output = reader.ReadToEnd();
Console.WriteLine(输出);
}
}

public interface IMyObject
{
string name {get;组; }
[DataContract]
public class MyObject:IMyObject
{
[DataMember]
public string name {get;组; }
}

[DataContract]
public class Result< T>
{
[DataMember]
public string Status {get;组; }

[DataMember]
public T Item {get;组; }
}

public abstract class BaseCommand
{
protected Result< IMyObject> results = new Result< IMyObject>();

公共结果< IMyObject>结果
{
得到{return this.results; }
}

public abstract void Execute();

$ b $ public class InterfaceCommand:BaseCommand
{
public override void Execute()
{
IMyObject myobject = new MyObject();
myobject.name =我的对象;
结果< IMyObject> result = new Result< IMyObject>();
result.Item = myobject;
result.Status =ok;
this.results = result;


$ b $公共类ConcreteCommand:BaseCommand
{
public override void Execute()
{
MyObject myobject =新的MyObject();
myobject.name =我的对象;
结果< IMyObject> result = new Result< IMyObject>();
result.Item = myobject;
result.Status =ok;
this.results = result;


$ b [DataContract]
public class Response
{
[DataMember]
public string ResponseStatus {get;组; }

[DataMember]
public Result< IMyObject>结果{get;组; }
}

输出...

  {__ type:Response:#ConsoleApplication2,ResponseStatus:ok,Results:{__ ty 
pe:ResultOfanyType: #ConsoleApplication2,Item:{__ type:MyObject:#ConsoleAp
plication2,name:my object},Status:ok}}

如果你试图制作某种通用契约,你将不得不拥有某种通用基类/接口。它不会与对象一起工作,但只要它们包含在已知类型中,您就可以使用ala COM并创建自己的IUnknown接口,从中创建尽可能多的子类。

I have a set of classes as follows: a Command, which Executes and stores a Result; a Response, which is created as in order to return the Result in a serialized form (plus extra metadata which I've left out). The Response.Result must be of type object, as it is used for a bunch of different commands, each of which can have a Result of any type at all.

The Command is generic, and I'd like it to accept an interface rather than concrete type, but when I do, the serialized response contains the following type hint:

"__type":"ResultOfanyType:#serialization"

rather than the following, which is generated when the command accepts a concrete type:

"__type":"ResultOfMyObjectDhOQ6IBI:#serialization"

I need the type hint to contain the concrete type rather than ResultOfanyType. Why are interfaces being treated differently in this context? Notice that when the Type is a direct property of the serialized Command, then the concrete type is contained in the type hint

I've tried changing the the Result's Response property typed to Result, but that has no effect.

Here is the code. Simply uncomment/comment the lines in Main where the command is created and known types listed for the alternative version.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace serialization
{
    class Program
    {
        static void Main(string[] args)
        {
            Response response = new Response();
            response.ResponseStatus = "ok";
            ConcreteCommand command = new ConcreteCommand();    //switch with line below to test inteface
            //InterfaceCommand command = new InterfaceCommand();
            command.Execute();
            response.Results = command.Results;
            List<Type> knownTypes = new List<Type>
            {
            typeof(Result<MyObject>),                  //switch with Interface lines below to test inteface
            typeof(MyObject)
            //typeof(Result<IMyObject>),
            //typeof(IMyObject)
            };
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(response.GetType(), knownTypes, int.MaxValue, false, null, true);
            Stream stream = new MemoryStream();
            serializer.WriteObject(stream, response);
            stream.Position = 0;
            StreamReader reader = new StreamReader(stream);
            string output = reader.ReadToEnd();
            Console.WriteLine(output);
        }
    }

    public interface IMyObject
    {
        string name { get; set; }
    }

    [DataContract]
    [KnownType(typeof(MyObject))]
    public class MyObject : IMyObject
    {
        [DataMember]
        public string name { get; set; }
    }

    [DataContract]
    public class Result<T>
    {
        [DataMember]
        public string Status { get; set; }

        [DataMember]
        public T Item { get; set; }
    }

    public abstract class BaseCommand<T>
    {
        protected Result<T> results = new Result<T>();

        protected T resultObject;

        public object Results
        {
            get { return this.results; }
        }

        public T ResultObject
        {
            get { return this.resultObject; }
        }

        public abstract void Execute();
    }

    public class InterfaceCommand : BaseCommand<IMyObject>
    {
        public override void Execute()
        {
            IMyObject myobject = new MyObject();
            myobject.name = "my object";
            Result<IMyObject> result = new Result<IMyObject>();
            result.Item = myobject;
            result.Status = "ok";
            this.results= result;
            this.resultObject = myobject;
        }
    }

    public class ConcreteCommand : BaseCommand<MyObject>
    {
        public override void Execute()
        {
            MyObject myobject = new MyObject();
            myobject.name = "my object";
            Result<MyObject> result = new Result<MyObject>();
            result.Item = myobject;
            result.Status = "ok";
            this.results = result;
            this.resultObject = myobject;
        }
    }

    [DataContract]
    public class Response
    {
        [DataMember]
        public string ResponseStatus { get; set; }

        [DataMember]
        public object Results { get; set; }
    }
}

解决方案

How about this...

class Program
{
    static void Main(string[] args)
    {
        Response response = new Response();
        response.ResponseStatus = "ok";
        //ConcreteCommand command = new ConcreteCommand();    //switch with line below to test inteface
        InterfaceCommand command = new InterfaceCommand();
        command.Execute();
        response.Results = command.Results;
        List<Type> knownTypes = new List<Type>
        {
            typeof(MyObject),
            typeof(Result<MyObject>)                  //switch with line below to test inteface
            //typeof(Result<IMyObject>)
        };
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(response.GetType(), knownTypes, int.MaxValue, false, null, true);
        Stream stream = new MemoryStream();
        serializer.WriteObject(stream, response);
        stream.Position = 0;
        StreamReader reader = new StreamReader(stream);
        string output = reader.ReadToEnd();
        Console.WriteLine(output);
    }
}

public interface IMyObject
{
    string name { get; set; }
}

[DataContract]
public class MyObject : IMyObject
{
    [DataMember]
    public string name { get; set; }
}

[DataContract]
public class Result<T>
{
    [DataMember]
    public string Status { get; set; }

    [DataMember]
    public T Item { get; set; }
}

public abstract class BaseCommand
{
    protected Result<IMyObject> results = new Result<IMyObject>();

    public Result<IMyObject> Results
    {
        get { return this.results; }
    }

    public abstract void Execute();
}

public class InterfaceCommand : BaseCommand
{
    public override void Execute()
    {
        IMyObject myobject = new MyObject();
        myobject.name = "my object";
        Result<IMyObject> result = new Result<IMyObject>();
        result.Item = myobject;
        result.Status = "ok";
        this.results= result;
    }
}

public class ConcreteCommand : BaseCommand
{
    public override void Execute()
    {
        MyObject myobject = new MyObject();
        myobject.name = "my object";
        Result<IMyObject> result = new Result<IMyObject>();
        result.Item = myobject;
        result.Status = "ok";
        this.results = result;
    }
}

[DataContract]
public class Response
{
    [DataMember]
    public string ResponseStatus { get; set; }

    [DataMember]
    public Result<IMyObject> Results { get; set; }
}

Outputs...

{"__type":"Response:#ConsoleApplication2","ResponseStatus":"ok","Results":{"__ty
pe":"ResultOfanyType:#ConsoleApplication2","Item":{"__type":"MyObject:#ConsoleAp
plication2","name":"my object"},"Status":"ok"}}

If you're trying to make some sort of generic contract, you're going to have to have some sort of common base class/interface. It won't work with object but you can go ala COM and make your own IUnknown interface from which to create as many subclasses as you like, as long as they are included within your known types.

这篇关于在从接口序列化泛型类时,如何让DataContractJsonSerializer在类型提示中使用具体类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆