将JSON反序列化为IEnumerable <t>对象时出错

时间:2018-04-13 14:40:16

标签: c# json.net deserialization ienumerable

我得到的错误如下:

  

{&#34;无法创建和填充列表类型ReasonCodeList。路径   &#39; AppointmentReasonList [0] .ReasonCodeList&#39;,第1行,第162位。&#34;}

转换以下示例JSON数据时出现此错误:

{
    "ErrorCode":""
    ,"ErrorMessage":""
    ,"AppointmentReasonList":[
        {
            "ClassCode":"851"
            ,"ClassDescription":"newpat"
            ,"Active":true
            ,"IsPatientRelated":true
            ,"ReasonCodeList":[
                {
                    "Code":"851"
                    ,"Description":"Emergency New Patient Visit"
                    ,"Duration":15
                    ,"Active":true
                }
                ,{
                    "Code":"BH NEW"
                    ,"Description":"BH NEW"
                    ,"Duration":15
                    ,"Active":true
                }
                            ]
        }
        ,{
            "ClassCode":"ANE"
            ,"ClassDescription":"Anesthesia"
            ,"Active":true
            ,"IsPatientRelated":true
            ,"ReasonCodeList":[
                {
                    "Code":"123456"
                    ,"Description":"This is only a test"
                    ,"Duration":15
                    ,"Active":true
                }
                                ]
        }                   
                            ]
}

我已经创建了以下类来尝试匹配数据结构。

public class AppointmentReasonResponse
        {
            public string ErrorCode { get; set; }
            public string ErrorMessage { get; set; }
            public List<AppointmentReason> AppointmentReasonList { get; set; }
        }

        public class AppointmentReason
        {
            public string ClassCode { get; set; }
            public string ClassDescription { get; set; }
            public bool Active { get; set; }
            public bool IsPatientRelated { get; set; }
            public ReasonCodeList ReasonCodeList { get; set; }
        }

        public class ReasonCodeList:IEnumerable<ReasonCode>
        {
            public List<ReasonCode> ReasonCodeLi { get; set; }

            IEnumerator<ReasonCode> IEnumerable<ReasonCode>.GetEnumerator()
            {
                // Return the array object's IEnumerator.
                foreach (ReasonCode Reason in ReasonCodeLi)
                {
                    yield return Reason;
                }
            }

            public IEnumerator<ReasonCode> GetEnumerator()
            {
                // Return the array object's IEnumerator.
                return ReasonCodeLi.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                // call the generic version of the method
                return this.GetEnumerator();
            }
        }

        public class ReasonCode
        {
            public string Code { get; set; }
            public string Description { get; set; }
            public int Duration { get; set; }
            public bool Active { get; set; }
        }

如果你已经做到这一点,我为大量的代码道歉,但我认为所有这些都是必要的细节。

最初我对此question收到同样的错误。

当我通过添加ReasonCodeList类来调整我的类结构时,我开始收到新错误。

最终目标是为JSON中的每个原因对象提取每个代码和描述,并将它们用作SQL过程中的参数。

这将需要两个foreach循环,而ReasonCodeList自定义集合必须实现IEnumerable才能这样做。

任何帮助将不胜感激。我不熟悉IEnumerable接口及其周围的限制。

修改

响应@Mr Hery:当我尝试按照您的建议构建AppointmentReason类时发生以下错误:

  

{&#34;无法反序列化当前的JSON对象(例如   {\&#34; name \&#34;:\&#34; value \&#34;})进入类型   ReasonCodeList&#39;因为类型需要   要正确反序列化的JSON数组(例如[1,2,3])。\ r \ n要解决这个问题   错误要么将JSON更改为JSON数组(例如[1,2,3]),要么更改   反序列化类型,以便它是一个普通的.NET类型(例如,不是   原始类型,如整数,而不是像数组或类似的集合类型   List)可以从JSON对象反序列化。   JsonObjectAttribute也可以添加到类型中以强制它   从JSON对象反序列化。\ r \ nPath   &#39; AppointmentReasonList [0] .ReasonCodeList [0] .Code&#39;,第1行,位置   170&#34;}

我最初使用ReasonCodeList属性构建此类,这是一种List类型,因为它本质上是什么但是得到了相同的错误。我尝试使用ReasonCodeList对象替换它,如前一个原始帖子部分中引用的答案中所建议的那样。

当我进行更改时,此问题最顶端的错误就是发生了什么。

编辑#2

回应@Frank Fajardo&amp;他的建议,这就是反序列化的AppointReasonResponse对象将被用于:

    jarray = JsonConvert.DeserializeObject<AppointmentReasonResponse>(json);
    foreach (AppointmentReason ApptReason in jarray.AppointmentReasonList)
    {
        foreach (ReasonCode Reason in ApptReason)
        {
            AddInterfacePMReasonCode(PracticeID, Reason.Code, Reason.Description);
        }
    }

由于以下错误导致类ReasonCode的属性:

  

错误105 foreach语句无法对类型变量进行操作   &#39; AppointmentReason&#39;因为&#39; AppointmentReason&#39;不包含   &#39; GetEnumerator&#39;

的公开定义

编辑3

正如@Frank Fajardo所指出的,编辑#2中的内部foreach循环正在查看AppointmentReason对象,而不是它的list属性。修复代码后,会返回一个错误,就像我在本文中发布的错误一样。

新的类对象和修改过的foreach循环:

public class AppointmentReasonResponse
        {
            public string ErrorCode { get; set; }
            public string ErrorMessage { get; set; }
            public AppointmentReasonList AppointmentReasonList { get; set; }
        }

        public class AppointmentReasonList : IEnumerable<AppointmentReason>
        {

            public List<AppointmentReason> AppointmentReasonLi { get; set; }

            IEnumerator<AppointmentReason> IEnumerable<AppointmentReason>.GetEnumerator()
            {
                foreach (AppointmentReason ApptReason in AppointmentReasonLi)
                {
                    yield return ApptReason;
                }
            }

            public IEnumerator<AppointmentReason> GetEnumerator()
            {
                return AppointmentReasonLi.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
        }

foreach (AppointmentReason ApptReason in jarray.AppointmentReasonList)
                {
                    foreach (ReasonCode Reason in ApptReason.ReasonCodeList)
                    {
                        AddInterfacePMReasonCode(PracticeID, Reason.Code, Reason.Description);
                    }
                }

收到错误:

  

{&#34;无法创建和填充列表类型AppointmentReasonList。路径   &#39; AppointmentReasonList&#39;,第1行,第59位。&#34;}

4 个答案:

答案 0 :(得分:1)

可能会将您的AppointmentReason更改为:

    public class AppointmentReason
    {
        public string ClassCode { get; set; }
        public string ClassDescription { get; set; }
        public bool Active { get; set; }
        public bool IsPatientRelated { get; set; }
        public List<ReasonCode> ReasonCodeList { get; set; }
    }

<强>更新

你的循环颂歌不正确。它应该是这样的(注意内部AppReason.ReasonCodeList循环中的AppReason而不仅仅是foreach

jarray = JsonConvert.DeserializeObject<AppointmentReasonResponse>(json);
foreach (AppointmentReason ApptReason in jarray.AppointmentReasonList)
{
    foreach (ReasonCode Reason in ApptReason.ReasonCodeList)
    {
        AddInterfacePMReasonCode(PracticeID, Reason.Code, Reason.Description);
    }
}

更新2

我不知道为什么您将AppointmentReasonResponse.AppointmentReasonList属性从List<AppointmentReason>类型更改为新类型AppointmentReasonList?但看起来你认为你需要引入一个实现枚举器的属性。但你不需要它。 A List<T> implements IEnumerable<T>.

所以你的课程应该是这样的:

    public class AppointmentReasonResponse
    {
        public string ErrorCode { get; set; }
        public string ErrorMessage { get; set; }
        public List<AppointmentReason> AppointmentReasonList { get; set; }
    }

    public class AppointmentReason
    {
        public string ClassCode { get; set; }
        public string ClassDescription { get; set; }
        public bool Active { get; set; }
        public bool IsPatientRelated { get; set; }
        public List<ReasonCode> ReasonCodeList { get; set; }
    }

    public class ReasonCode
    {
        public string Code { get; set; }
        public string Description { get; set; }
        public int Duration { get; set; }
        public bool Active { get; set; }
    }

然后按照我的说明进行反序列化并使用它。

答案 1 :(得分:0)

错误表明cannot create and populate list是因为您的代码中缺少List<>。以下是更正:

public class AppointmentReasonResponse
{
    public string ErrorCode { get; set; }
    public string ErrorMessage { get; set; }
    public List<AppointmentReason> AppointmentReasonList { get; set; }
}

public class AppointmentReason
{
    public string ClassCode { get; set; }
    public string ClassDescription { get; set; }
    public bool Active { get; set; }
    public bool IsPatientRelated { get; set; }
    public List<ReasonCodeList> ReasonCodeList { get; set; }
}

public class ReasonCodeList:IEnumerable<ReasonCode>
{
    public List<ReasonCode> ReasonCodeLi { get; set; }

    IEnumerator<ReasonCode> IEnumerable<ReasonCode>.GetEnumerator()
    {
        // Return the array object's IEnumerator.
        foreach (ReasonCode Reason in ReasonCodeLi)
        {
            yield return Reason;
        }
    }

    public IEnumerator<ReasonCode> GetEnumerator()
    {
        // Return the array object's IEnumerator.
        return ReasonCodeLi.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        // call the generic version of the method
        return this.GetEnumerator();
    }
}

public class ReasonCode
{
    public string Code { get; set; }
    public string Description { get; set; }
    public int Duration { get; set; }
    public bool Active { get; set; }
}

您的JSON返回一个数组数据,因此您需要放置List<>

答案 2 :(得分:0)

感谢大家提出的所有建议。我在一个单独的论坛上发布了这个问题,并收到了Eric Lynch在codeproject.com上的答案

您可以在此处查看他的答案:https://www.codeproject.com/Questions/1241686/JSON-deserializer-cannot-create-populate-object

正如Eric和@Frank Fajardo指出的那样,AppointmentReasonListReasonCodeList类都不需要实现IEnumerable{T},因为List{T}类型已经实现了接口。< / p>

出于某种原因,您必须定义从List{T}继承的类并将该类用作集合类型,而不是仅仅定义类型List{T}的属性本身。

我不确定为什么会这样,因为两种方法似乎都在做同样的事情,但是在使用第二种方法时,当您尝试迭代生成的对象时会出现以下错误:

  

错误105 foreach语句无法对类型变量进行操作   &#39; AppointmentReason&#39;因为&#39; AppointmentReason&#39;不包含   &#39; GetEnumerator&#39;

的公开定义

不确定为什么会这样,但最终,Eric Lynch的回答提供了理想的结果。

答案 3 :(得分:-1)

当你拥有JSON时,不要手工制作课程或猜测它们,只需转到http://json2csharp.com,插入JSON,然后让它为你生成课程。

public class ReasonCodeList
{
    public string Code { get; set; }
    public string Description { get; set; }
    public int Duration { get; set; }
    public bool Active { get; set; }
}

public class AppointmentReasonList
{
    public string ClassCode { get; set; }
    public string ClassDescription { get; set; }
    public bool Active { get; set; }
    public bool IsPatientRelated { get; set; }
    public List<ReasonCodeList> ReasonCodeList { get; set; }
}

public class RootObject
{
    public string ErrorCode { get; set; }
    public string ErrorMessage { get; set; }
    public List<AppointmentReasonList> AppointmentReasonList { get; set; }
}

var root = JsonConvert.DeserializeObject<RootObject>(json);

foreach (var appointmentReason in root.AppointmentReasonList)
{
    foreach (var reasonCode in appointmentReason.ReasonCodeList)
    {
        Console.WriteLine($"Code: {reasonCode.Code}; Description {reasonCode.Description}");
    }
}

鉴于您原来的JSON,上面产生了以下输出。

  

代码:851;描述紧急新患者就诊

     

代码:BH NEW;说明BH NEW

     

代码:123456;说明这只是一个测试

我还在https://dotnetfiddle.net/170Xob创建了一个小提琴。