为什么Json可序列化类型必须具有公共的无参数构造函数?

时间:2014-06-03 11:54:32

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

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

当我想 JSON序列化返回的列表时,它会给我一个例外 InvalidOperationException(“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; 
   }

1 个答案:

答案 0 :(得分: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; }
}