将JSON反序列化为通用对象

3

我有三个类

public class A<T>
{
    public bool Success {get; set;}
    public string Reason {get; set;}
    public T Data {get; set;}
}

public class B
{ 
    public string Token {get; set;}
}

public class C
{
    public int SomeInt {get; set;}
    public string SomeString {get; set;}
    public double SomeDouble {get; set;}
}

我调用我的Web服务并传入A或A以进行反序列化,如下所示:
 async Task<T> MyTask<T>(...) (where T is A<B> or A<C>)

这个服务正常工作并返回一些JSON数据,但是如果我尝试将其反序列化为一个变量,我得到的结果为空。

我使用以下方法进行反序列化:

 var foo = JsonConvert.DeserializeObject<T>(response.Content);

我可以只使用基类来反序列化对象吗,是否有限制?


我不明白你上一句话的意思,这似乎是你问题的关键所在。 - undefined
在反序列化过程中,我只能传入A而不能传入A<B>吗? - undefined
1
你需要在你的 Web 服务调用中添加一个额外的通用参数 async Task<T1> MyTask<T1,T2>(...) where T2 : class where T1 : A<T2> - 然后你可以反序列化 var foo = JsonConvert.DeserializeObject<T1>(response.Content) 并调用你的 Web 服务 await MyTask<A<B>, B>() - undefined
2个回答

4

是的,你不能只传递A,因为A不是基类,它是泛型类而且自身并不存在。

C#在编译时生成泛型类,这意味着如果你在代码中使用A<B>,C#会生成类似以下的内容:

public class generated_A_B
{
    public bool Success { get; set; }
    public string Reason { get; set; }
    public B Data { get; set; }
}

如果没有明确使用,将不会为A<C>生成任何内容。原因很明显,如果为每个A的组合生成类,则会使代码臃肿。

在当前情况下,最好直接显式调用它们。

void Main()
{
    CallAB();
    CallAC();
}

A<B> CallAB()
{
    return ServiceCall<A<B>>("/api/ab");
}

A<C> CallAC()
{
    return ServiceCall<A<C>>("/api/ac");
}

如果您真的想要获得“通用”的A,您应该将A变成一个实际的基类,并让API返回Data的类型。在我的示例中,我只使用了类型的Name,但您可能应该使用包含命名空间的FullName,以避免名称冲突。

void Main()
{
    var json = @"
    {
        ""success"": true,
        ""reason"": ""All good"",
        ""type"": ""B"",
        ""data"": {
            ""token"": ""1234-5678""
        }
    }";
    var foo = JsonConvert.DeserializeObject<A>(json);
    var type = Assembly.GetExecutingAssembly().GetTypes().Where(i => i.IsClass && i.Name == foo.Type).FirstOrDefault();
    if (type == null)
    {
        throw new InvalidOperationException(string.Format("Type {0} not found", foo.Type));
    }
    var data = foo.Data.ToObject(type);
}

public class A
{
    public bool Success { get; set; }
    public string Reason { get; set; }
    public string Type { get; set; }
    public JToken Data { get; set; }
}

public class B
{
    public string Token { get; set; }
}

0
我建议采用简单的解决方案:创建一个中间合并了你的类BC的类,类似于这样。
    public class BC
    {
        public string Token { get; set; }
        public int SomeInt { get; set; }
        public string SomeString { get; set; }
        public double SomeDouble { get; set; }

        public bool IsB => !String.IsNullOrEmpty(Token);

        public B ToB() => new B() { Token = Token };

        public C ToC() => new C() { SomeInt = SomeInt, SomeString = SomeString, SomeDouble = SomeDouble };
    }

然后你可以调用你的服务,并将BC转换为BC
async Task<A<BC>> MyTask<A<BC>>(...)
var abc = await MyTask(...);
if(abc.Data.IsB)
{
    var resB = abc.data.ToB();
}
else
{
    var resC = abc.data.ToC();
}

或者选择更复杂的解决方案,使用一些JsonConverter,如本答案中所解释的:

如何在Json.Net中实现自定义JsonConverter以反序列化基类列表


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接