Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# JSON.net:如何在不使用默认构造函数的情况下反序列化?_C#_Json_Json.net - Fatal编程技术网

C# JSON.net:如何在不使用默认构造函数的情况下反序列化?

C# JSON.net:如何在不使用默认构造函数的情况下反序列化?,c#,json,json.net,C#,Json,Json.net,我有一个类,它有一个默认构造函数,还有一个重载构造函数,它接受一组参数。这些参数与对象上的字段匹配,并在构造时指定。此时,我需要用于其他目的的默认构造函数,因此如果可以的话,我希望保留它 我的问题:如果我删除默认构造函数并传入JSON字符串,对象将正确反序列化并传入构造函数参数,而不会出现任何问题。我最终得到了我所期望的填充对象。但是,只要我将默认构造函数添加到对象中,当我调用JsonConvert.DeserializeObject(jsontext)时,属性就不再填充 此时,我已尝试将新Js

我有一个类,它有一个默认构造函数,还有一个重载构造函数,它接受一组参数。这些参数与对象上的字段匹配,并在构造时指定。此时,我需要用于其他目的的默认构造函数,因此如果可以的话,我希望保留它

我的问题:如果我删除默认构造函数并传入JSON字符串,对象将正确反序列化并传入构造函数参数,而不会出现任何问题。我最终得到了我所期望的填充对象。但是,只要我将默认构造函数添加到对象中,当我调用
JsonConvert.DeserializeObject(jsontext)
时,属性就不再填充

此时,我已尝试将
新JsonSerializerSettings(){CheckAdditionalContent=true}
添加到反序列化调用中。那没有任何作用

另一个注意事项:构造函数参数确实与字段名称完全匹配,只是参数以小写字母开头。我认为这无关紧要,因为正如我提到的,反序列化在没有默认构造函数的情况下工作得很好

以下是我的构造函数示例:

public Result() { }

public Result(int? code, string format, Dictionary<string, string> details = null)
{
    Code = code ?? ERROR_CODE;
    Format = format;

    if (details == null)
        Details = new Dictionary<string, string>();
    else
        Details = details;
}
public Result(){}
公共结果(int?代码、字符串格式、字典详细信息=null)
{
代码=代码??错误\代码;
格式=格式;
如果(详细信息==null)
详细信息=新字典();
其他的
细节=细节;
}

Json.Net更喜欢在对象上使用默认(无参数)构造函数(如果有)。如果有多个构造函数,并且希望Json.Net使用非默认构造函数,则可以向希望Json.Net调用的构造函数添加
[JsonConstructor]
属性

[JsonConstructor]
public Result(int? code, string format, Dictionary<string, string> details = null)
{
    ...
}
然后,将转换器添加到序列化程序设置中,并在反序列化时使用这些设置:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new ResultConverter());
Result result = JsonConvert.DeserializeObject<Result>(jsontext, settings);
JsonSerializerSettings设置=新建JsonSerializerSettings();
settings.Converters.Add(newresultconverter());
结果=JsonConvert.DeserializeObject(jsontext,设置);

有点晚了,不太适合这里,但我要在这里添加我的解决方案,因为它已作为此解决方案的副本关闭,而且此解决方案完全不同

我需要一种通用的方法来指示
Json.NET
为用户定义的结构类型选择最具体的构造函数,因此我可以省略
jsonstructor
属性,这将为定义每个此类结构的项目添加一个依赖项

我已经进行了一些反向工程,并实现了一个自定义契约解析器,其中我覆盖了
CreateObjectContract
方法来添加自定义创建逻辑

public class CustomContractResolver : DefaultContractResolver {

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var c = base.CreateObjectContract(objectType);
        if (!IsCustomStruct(objectType)) return c;

        IList<ConstructorInfo> list = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).OrderBy(e => e.GetParameters().Length).ToList();
        var mostSpecific = list.LastOrDefault();
        if (mostSpecific != null)
        {
            c.OverrideCreator = CreateParameterizedConstructor(mostSpecific);
            c.CreatorParameters.AddRange(CreateConstructorParameters(mostSpecific, c.Properties));
        }

        return c;
    }

    protected virtual bool IsCustomStruct(Type objectType)
    {
        return objectType.IsValueType && !objectType.IsPrimitive && !objectType.IsEnum && !objectType.Namespace.IsNullOrEmpty() && !objectType.Namespace.StartsWith("System.");
    }

    private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
    {
        method.ThrowIfNull("method");
        var c = method as ConstructorInfo;
        if (c != null)
            return a => c.Invoke(a);
        return a => method.Invoke(null, a);
    }
}
公共类CustomContractResolver:DefaultContractResolver{
受保护的重写JsonObjectContract CreateObjectContract(类型objectType)
{
var c=base.CreateObjectContract(objectType);
如果(!IsCustomStruct(objectType))返回c;
IList list=objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).OrderBy(e=>e.GetParameters().Length).ToList();
var mostsspecific=list.LastOrDefault();
if(mostSpecific!=null)
{
c、 OverrideCreator=CreateParameterizedConstructor(MOSTSSpecific);
c、 AddRange(CreateConstructorParameters(mostSpecific,c.Properties));
}
返回c;
}
受保护的虚拟bool IsCustomStruct(类型objectType)
{
返回objectType.IsValueType&!objectType.IsPrimitive&!objectType.IsEnum&&!objectType.Namespace.IsNullOrEmpty()&&!objectType.Namespace.StartWith(“系统”);
}
私有ObjectConstructor CreateParameterizedConstructor(MethodBase方法)
{
方法:ThrowIfNull(“方法”);
var c=作为构造函数信息的方法;
如果(c!=null)
返回a=>c.Invoke(a);
返回a=>method.Invoke(null,a);
}
}
我是这样用的

public struct Test {
  public readonly int A;
  public readonly string B;

  public Test(int a, string b) {
    A = a;
    B = b;
  }
}

var json = JsonConvert.SerializeObject(new Test(1, "Test"), new JsonSerializerSettings {
  ContractResolver = new CustomContractResolver()
});
var t = JsonConvert.DeserializeObject<Test>(json);
t.A.ShouldEqual(1);
t.B.ShouldEqual("Test");
公共结构测试{
公共只读INTA;
公共只读字符串B;
公共测试(int a,string b){
A=A;
B=B;
}
}
var json=JsonConvert.SerializeObject(新测试(1,“测试”),新JsonSerializerSettings{
ContractResolver=新的CustomContractResolver()
});
var t=JsonConvert.DeserializeObject(json);
t、 A.ShouldEqual(1);
t、 B.应合格(“试验”);

基于这里的一些答案,我已经编写了一个
CustomConstructor Resolver
用于当前项目,我认为它可能会帮助其他人

它支持以下所有可配置的解析机制:

  • 选择一个私有构造函数,这样就可以定义一个私有构造函数,而不必用属性标记它
  • 选择最具体的私有构造函数,这样就可以有多个重载,而不必使用属性
  • 选择标记有特定名称属性的构造函数-与默认解析器类似,但不依赖于Json.Net包,因为您需要引用
    Newtonsoft.Json.JsonConstructorAttribute
公共类CustomConstructorResolver:DefaultContractResolver
{
公共字符串ConstructorAttributeName{get;set;}=“JsonConstructorAttribute”;
public bool IgnoreAttributeConstructor{get;set;}=false;
public bool IgnoreSinglePrivateConstructor{get;set;}=false;
public bool IgnoreMostSpecificConstructor{get;set;}=false;
受保护的重写JsonObjectContract CreateObjectContract(类型objectType)
{
var contract=base.CreateObjectContract(objectType);
//对非对象类型使用默认约定。
if(objectType.IsPrimitive | | objectType.IsEnum)返回合同;
//首先查找具有属性的构造函数,然后是单个私有构造函数,然后是最特定的构造函数。
变量重写构造函数=
(此为
public struct Test {
  public readonly int A;
  public readonly string B;

  public Test(int a, string b) {
    A = a;
    B = b;
  }
}

var json = JsonConvert.SerializeObject(new Test(1, "Test"), new JsonSerializerSettings {
  ContractResolver = new CustomContractResolver()
});
var t = JsonConvert.DeserializeObject<Test>(json);
t.A.ShouldEqual(1);
t.B.ShouldEqual("Test");
public class CustomConstructorResolver : DefaultContractResolver
{
    public string ConstructorAttributeName { get; set; } = "JsonConstructorAttribute";
    public bool IgnoreAttributeConstructor { get; set; } = false;
    public bool IgnoreSinglePrivateConstructor { get; set; } = false;
    public bool IgnoreMostSpecificConstructor { get; set; } = false;

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

        // Use default contract for non-object types.
        if (objectType.IsPrimitive || objectType.IsEnum) return contract;

        // Look for constructor with attribute first, then single private, then most specific.
        var overrideConstructor = 
               (this.IgnoreAttributeConstructor ? null : GetAttributeConstructor(objectType)) 
            ?? (this.IgnoreSinglePrivateConstructor ? null : GetSinglePrivateConstructor(objectType)) 
            ?? (this.IgnoreMostSpecificConstructor ? null : GetMostSpecificConstructor(objectType));

        // Set override constructor if found, otherwise use default contract.
        if (overrideConstructor != null)
        {
            SetOverrideCreator(contract, overrideConstructor);
        }

        return contract;
    }

    private void SetOverrideCreator(JsonObjectContract contract, ConstructorInfo attributeConstructor)
    {
        contract.OverrideCreator = CreateParameterizedConstructor(attributeConstructor);
        contract.CreatorParameters.Clear();
        foreach (var constructorParameter in base.CreateConstructorParameters(attributeConstructor, contract.Properties))
        {
            contract.CreatorParameters.Add(constructorParameter);
        }
    }

    private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
    {
        var c = method as ConstructorInfo;
        if (c != null)
            return a => c.Invoke(a);
        return a => method.Invoke(null, a);
    }

    protected virtual ConstructorInfo GetAttributeConstructor(Type objectType)
    {
        var constructors = objectType
            .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .Where(c => c.GetCustomAttributes().Any(a => a.GetType().Name == this.ConstructorAttributeName)).ToList();

        if (constructors.Count == 1) return constructors[0];
        if (constructors.Count > 1)
            throw new JsonException($"Multiple constructors with a {this.ConstructorAttributeName}.");

        return null;
    }

    protected virtual ConstructorInfo GetSinglePrivateConstructor(Type objectType)
    {
        var constructors = objectType
            .GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);

        return constructors.Length == 1 ? constructors[0] : null;
    }

    protected virtual ConstructorInfo GetMostSpecificConstructor(Type objectType)
    {
        var constructors = objectType
            .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .OrderBy(e => e.GetParameters().Length);

        var mostSpecific = constructors.LastOrDefault();
        return mostSpecific;
    }
}
internal Result() { }

public Result(int? code, string format, Dictionary<string, string> details = null)
{
    Code = code ?? ERROR_CODE;
    Format = format;

    if (details == null)
        Details = new Dictionary<string, string>();
    else
        Details = details;
}
public Response Get(string jsonData) {
    var json = JsonConvert.DeserializeObject<modelname>(jsonData);
    var data = StoredProcedure.procedureName(json.Parameter, json.Parameter, json.Parameter, json.Parameter);
    return data;
}
public class modelname {
    public long parameter{ get; set; }
    public int parameter{ get; set; }
    public int parameter{ get; set; }
    public string parameter{ get; set; }
}