我有一个JSON字符串,例如
{
"first_name": "Paul"
"company": {
"company_name": "Microsoft"
}
}
我的班级是以下结构
[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找到一个接口的实现(从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接口上找到名为company_name的成员(显然它不能像在Company对象类上设置那样)
为什么JSON.NET不使用Company对象中的DataMember名称进行反序列化?因为它知道自定义解析器中的Compmany对象,它创建了该对象,但内部没有值。
如何让它使用接口的实现而不是接口本身?
仅供参考,这不是整个对象,我不能只将属性更改为类而不是接口。这只是所有界面对象发生的一个简洁示例。
答案 0 :(得分:2)
我遇到了同样的问题,在寻找答案的过程中,我发现了你的旧问题。实际上你问它的方式让我走上正轨,我解决了问题。以下适用于我:
我不使用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;
}
}
应使用在依赖性容器中注册的具体实现而不是接口来创建契约。 从容器中为DefaultCreator解析类型显然仍然应该使用接口。