【问题标题】:Why Json serializable types must have a public, parameterless constructor?为什么 Json 可序列化类型必须有一个公共的、无参数的构造函数?
【发布时间】:2014-06-03 11:54:31
【问题描述】:

我有一个方法,它有一个字符串类型参数返回一个列表,其中Tasks是我定义的一个类。

当我想要 JSON 序列化 返回的 List 时,它会给我一个 ExceptionInvalidOperationException("Json 可序列化类型必须有一个公共的、无参数的构造函数");

我该怎么办?


更新:添加了代码示例

我的班级是这样的:

public class Tasks
{
    public int _taskReprogramat;

    public int TaskReprogramat{ get; set; }
    
 
    public string TaskName {get; set; }
  
    public string Description{get; set; }
 
    public string IntreOrele{get; set; }
   
    public DateTime AssignDate{get; set; }
    
    public string Status{get; set; }

    public Tasks() { }
}            

我有以下课程:

public class DataContractJsonSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
    public DataContractJsonSerializerOperationBehavior(OperationDescription operation) : base(operation) { }

    public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
    {
        return new DataContractJsonSerializer(type);
    }

    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
    {
        return new DataContractJsonSerializer(type);
    }
}                                                             

public class JsonDataContractBehaviorAttribute : Attribute, IContractBehavior
{
        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            this.ReplaceSerializerOperationBehavior(contractDescription);
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
        {
            this.ReplaceSerializerOperationBehavior(contractDescription);
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
            foreach (OperationDescription operation in contractDescription.Operations)
            {
                foreach (MessageDescription message in operation.Messages)
                {
                    this.ValidateMessagePartDescription(message.Body.ReturnValue);
                    foreach (MessagePartDescription part in message.Body.Parts)
                    {
                        this.ValidateMessagePartDescription(part);
                    }

                    foreach (MessageHeaderDescription header in message.Headers)
                    {
                        this.ValidateJsonSerializableType(header.Type);
                    }
                }
            }
        }

        private void ReplaceSerializerOperationBehavior(ContractDescription contract)
        {
            foreach (OperationDescription od in contract.Operations)
            {
                for (int i = 0; i < od.Behaviors.Count; i++)
                {
                    DataContractSerializerOperationBehavior dcsob = od.Behaviors[i] as DataContractSerializerOperationBehavior;
                    if (dcsob != null)
                    {
                        od.Behaviors[i] = new DataContractJsonSerializerOperationBehavior(od);
                    }
                }
            }
        }

        private void ValidateMessagePartDescription(MessagePartDescription part)
        {
            if (part != null)
            {
                this.ValidateJsonSerializableType(part.Type);
            }
        }

        private void ValidateJsonSerializableType(Type type )
        {
            if (type != typeof(void))
            {
                if (!type.IsPublic)
                {
                    throw new InvalidOperationException("Json serialization is supported in public types only");
                }

                ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]);
                if (!type.IsPrimitive && defaultConstructor == null )
                {
                    throw new InvalidOperationException("Json serializable types must have a public, parameterless constructor");
                }
                
            }

        }
    }                                                          

我使用 Tasks 类的方法是:

    public List<Tasks> GetTask(string admin, DateTime date)
    {
        List<Tasks> tasks = new List<Tasks>();

        

        string conn = ConfigurationManager.ConnectionStrings["qtmConnectionString"].ConnectionString;
        SqlConnection myConn = new SqlConnection(conn);
        myConn.Open();

        SqlCommand myCommand = new SqlCommand("tasks", myConn);
        myCommand.CommandType = CommandType.StoredProcedure;

        myCommand.Parameters.Add("@username", SqlDbType.NChar);
        myCommand.Parameters["@username"].Value = admin;
        myCommand.Parameters.AddWithValue("@date", date);

        SqlDataReader reader = myCommand.ExecuteReader();

        string status = null;
        string intreOrele = null;
        Tasks task = new Tasks();
        task.TaskName = reader[1].ToString();
        task.Description = reader[2].ToString();
        task.IntreOrele = intreOrele;
        task.AssignDate = Convert.ToDateTime(reader[5]);
        task.Status = status;
        tasks.Add(task);  return tasks; 
   }

【问题讨论】:

  • 你用什么把它序列化成 JSON? (至少有三种常用的序列化工具……)
  • 有很多蹩脚的反序列化器不支持带参数的构造函数。

标签: c# .net json serialization primitive-types


【解决方案1】:

问题是您要反序列化的类没有公共的无参数构造函数。它可能看起来像这样:

public class Person
{
   public Person(int id, string name)
   {
      this.id = id;
      this.person = person;
   }

   private int id;
   private string name;

   public string Name { get { return this.name; } }

   public int Id { get { return this.id; } }
}

问题是 JSON 序列化器需要这样做:

var obj = new Person();
obj.Id = jsonParser.Get<int>("id");
obj.Name = jsonParser.Get<string>("name");

这样通过构造函数是不够聪明(或设计)的:

var obj = new Person( jsonParser.Get<int>("id"), jsonParser.Get<string>("name") );

所以改变你的班级来做到这一点:

public class Person
{
   public Person(int id, string name)
   {
      this.Id = id;
      this.Person = person;
   }

   // Parameterless constructor here
   public Person()
   {
   }

   public string Name { get ; set; }
   public int Id { get;set; }
}

【讨论】:

  • 这完全取决于 OP 使用的序列化器。 Person 的第一个版本可以使用,例如,Json.Net var person = JsonConvert.DeserializeObject&lt;Person&gt;(@"{""Id"":1,""Name"":""Joe""}");
猜你喜欢
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-04
  • 2012-10-21
相关资源
最近更新 更多