c# - JSON.NET 将接口(interface)反序列化为属性名称

标签 c# json json.net deserialization datamember

我有一个 JSON 字符串,例如

{
  "first_name": "Paul"
  "company": {
    "company_name": "Microsoft"
  }
}

我的类(class)结构如下

[DataContract]
class User {
  [DataMember(Name = "first_name")]
  public string FirstName { get; set; }

  [DataMember(Name = "company")]
  public ICompany Company { get; set; }
}

interface ICompany {
  string CompanyName { get; set; }
}

[DataContract]
class Company : ICompany {
  [DataMember(Name = "company_name")]
  public string CompanyName { get; set; }
}

我使用自定义自动解析器,它只是使用 autofac 查找接口(interface)的实现(从 json.net 网站拉取)

public class AutofacContractResolver : DefaultContractResolver
    {
        private readonly IContainer _container;

        public AutofacContractResolver(IContainer container)
        {
            _container = container;
        }

        protected override JsonObjectContract CreateObjectContract(Type objectType)
        {
            JsonObjectContract contract = base.CreateObjectContract(objectType);

            // use Autofac to create types that have been registered with it
            if (_container.IsRegistered(objectType))
            {
                contract.DefaultCreator = () => _container.Resolve(objectType);
            }

            return contract;
        }
    }

然后我使用反序列化 json 字符串

User user = JsonConvert.DeserializeObject<User>(json, new JsonSerializerSettings
                {
                    ContractResolver = _resolver,

                });

现在,当我反序列化 json 时,first_name 被序列化到 FirstName 属性中,但 company_name 没有,它只是返回 null。当我使用 TraceWriter 时,它指出它无法在 ICompany 接口(interface)上找到名为 company_name 的成员(显然不能,因为它是在 Company 对象类上设置的)

为什么 JSON.NET 不使用 Company 对象中的 DataMember 名称进行反序列化?因为它从自定义解析器中了解了 Compmany 对象,并且它创建了该对象,但内部没有任何值。

如何让它使用接口(interface)的实现而不是接口(interface)本身?

仅供引用,这不是整个对象,我不能只是将属性更改为类而不是接口(interface)。这只是所有接口(interface)对象所发生情况的精简示例。

最佳答案

我刚刚遇到了同样的问题,在寻找答案时我在这里找到了你的老问题。事实上,你问的方式让我走上了正轨,我解决了问题。以下对我有用:

我不使用 Autofac,所以这是伪代码。但理解它应该就足够了:

public class AutofacContractResolver : DefaultContractResolver
{
    private readonly IContainer _container;

    public AutofacContractResolver(IContainer container)
    {
        _container = container;
    }

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        JsonObjectContract contract;

        // use Autofac to create types that have been registered with it
        if (_container.IsRegistered(objectType))
        {
            //get the class that is mapped to the interface from autofac
            Type mappedType = _container.GetMappedTypeForRegisteredType(objectType);

            //so for example when objectType now contains 'ICompany'
            //then mappedType now should contain 'Company'

            //now use the mappedType to create the contract
            contract = base.CreateObjectContract(mappedType);

            //but still use the objectType for resolving
            contract.DefaultCreator = () => _container.Resolve(objectType);
        }
        else
            contract = base.CreateObjectContract(objectType);

        return contract;
    }
}

应使用在依赖项容器中注册的具体实现而不是接口(interface)来创建合约。 从容器中解析 DefaultCreator 的类型显然仍应使用该接口(interface)。

关于c# - JSON.NET 将接口(interface)反序列化为属性名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38834073/

相关文章:

javascript - 循环遍历json

c# - WebAPI 返回没有根节点的 JSON 数组

json - 如何获取Newtonsoft.Json反序列化值的未转义字符串值?

c# - 如何在c#字段中转换json数组字段

c# - LINQ 按对象类型选择

c# - 线程并行编程

php - 接收来自 PHP 的 JSON 请求

c# - 压栈方式

c# - 中欧是否有通用的 TimeZoneInfo?

xml - 我应该在 Android 应用程序中使用 XML 还是 JSON 作为数据格式?