[英]How do I get DataContractJsonSerializer to use concrete type in type hint when serializing generic class from interface
我有一組如下的類:一個命令,執行並存儲一個結果; 響應,其創建目的是為了以序列化形式返回結果(加上我遺漏的其他元數據)。 Response.Result 必須為object類型,因為它用於一堆不同的命令,每個命令都可以具有任何類型的Result。
該命令是通用的,我希望它接受接口而不是具體類型,但是當我這樣做時,序列化響應包含以下類型提示:
"__type":"ResultOfanyType:#serialization"
而不是以下命令,它是在命令接受具體類型時生成的:
"__type":"ResultOfMyObjectDhOQ6IBI:#serialization"
我需要類型提示來包含具體類型而不是ResultOfanyType。 為什么在這種情況下對接口進行不同的對待? 請注意,當Type是序列化Command的直接屬性時,則具體類型包含在類型提示中
我嘗試將類型為Result的Result的Response屬性更改為Result,但這無效。
這是代碼。 只需取消注釋/注釋Main中創建命令的行,並列出替代版本的已知類型。
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; }
}
}
讓我們從這個問題開始,它可以解釋一切。
我需要類型提示來包含具體類型而不是ResultOfanyType。 為什么在這種情況下對接口進行不同的對待?
一個接口基本上只是一個實現它的類應包含的協定,而多個類可以實現其成員。 例如。
public interface IPerson
{
int Id { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
}
public class Person : IPerson
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class Contact : IPerson
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public string PhoneNumber { get; set; }
}
因此,當您致電IPerson
,您會期待什么? 一個Person
還是一個Contact
? 每個都有一個ID和一個名稱的基本組成部分,但每個都有IPerson
甚至不知道存在的獨特屬性。 這就是為什么當您嘗試獲取一個接口來解析為具體的類時,如果沒有某種工廠類來弄清楚您想要的東西,您將無所適從。 因此,在這種情況下,如果要解析IPerson
,請添加以下代碼行...
var objectType = iPersonObject.GetType();
對於您的情況,您想嘗試在result.Item
上調用GetType()
。 這告訴.NET查看實現接口的對象的實際類型並返回它。
這個怎么樣...
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; }
}
輸出...
{"__type":"Response:#ConsoleApplication2","ResponseStatus":"ok","Results":{"__ty
pe":"ResultOfanyType:#ConsoleApplication2","Item":{"__type":"MyObject:#ConsoleAp
plication2","name":"my object"},"Status":"ok"}}
如果您要制定某種通用合同,則必須具有某種通用的基類/接口。 它不適用於對象,但是您可以在COM上創建自己的IUnknown接口,從中創建任意數量的子類,只要它們包含在已知類型中即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.