Newtonsoft PopulateObject - значение не может быть нулевым исключением - PullRequest
0 голосов
/ 16 января 2019

Я пытаюсь заполнить существующий экземпляр пользовательского перечислимого объекта, который содержит объекты, включающие enum свойства. Когда я это делаю, я получаю ошибку System.ArgumentNullException: Value cannot be null от JsonConvert.PopulateObject(). Что может быть причиной этого? Вот мой образец:

https://dotnetfiddle.net/CLYN3L

Я пытаюсь выяснить, являются ли какие-либо из следующих причин ниже:

  1. с перечислениями в моем классе.

  2. мой класс наследует IEnumerator, IEnumerable.

У меня есть классы и перечисления ниже, которые я не могу контролировать. Я не могу их изменить:

public enum ErrorDisplayType : int 
{
    PopUp = 0,
    ErrorPane = 1,
    Statusbar = 2
}

[Serializable()]
public class ErrorObj 
{
   private string errorCode;
   private ErrorDisplayType errorDispType;

   public string ErrorCode 
   {
     get { return this.errorCode; }
     set {
        this.errorCode = value;
        if (errorCode != null)
        {
           this.setFields(errorCode);
        }
     }
   }
   public ErrorDisplayType ErrorDispType 
   {
      get { return this.errorDispType; }
      set { this.errorDispType = value; }
   }

    private void setFields(string errorCode) 
    {
       this.errorDispType = (ErrorDisplayType)int.Parse(errorCode);
    }   
}

[Serializable]
public class ErrorDTO : IEnumerator, IEnumerable 
{
   private int indx = -1;
   private List<ErrorObj> errorList;

   public List<ErrorObj> ErrorList 
   {
     get { return this.errorList; }
     set { this.errorList = value; }
   }

   public ErrorDTO()
   {
        this.errorList = new List<ErrorObj>();
   }

   public int Add(ErrorObj error)
   {
    this.errorList.Add(error);
    return 0;  
   }

   public bool MoveNext()
   {
      if (indx < errorList.Count - 1)      
      {                                    
         ++indx;                          
         return true;                     
      }                                    
      else                                 
      {                                    
         indx = -1;                       
         return false;                    
      }                                    
    }

    public void Reset()
    {
      this.indx = -1;
    }

    public object Current                                                            
    {                                                                               
       get                                                                          
       {                                                                            
         if (errorList.Count == 0 || indx < 0 || indx > errorList.Count - 1)
         { 
            return null;                                                         
         }
         return this.errorList[indx];                                             
       }                                                                            
    } 
    public IEnumerator GetEnumerator()  
    {
      return (IEnumerator)this;
    }

}

У меня есть метод (который я не могу изменить), который дает мне строку JSON, как показано ниже

[{
    "ErrorCode": "ABCD125",
    "ErrorDispType": 1
}]

Который я генерирую следующим образом:

// below is already existing code
private static ErrorObj CreateErrorObj(string errorCode)
{
   ErrorObj error = new ErrorObj();
   error.ErrorCode = "ABCD125";
   error.ErrorDispType = (ErrorDisplayType)int.Parse(errorCode);
   return error;    
}

public string GetErrorJSON()
{
  ErrorDTO errDTO = new ErrorDTO();
  ErrorObj errObj = CreateErrorObj("1");
  errDTO.Add(errObj);

  string returnValue = Newtonsoft.Json.JsonConvert.SerializeObject(errDTO);
  return returnValue;
 }

Ниже мой код, и я пытаюсь десериализовать

ErrorDTO errorDTO = new ErrorDTO();
string jsonString = GetErrorJSON();

Ниже строки выдает ошибку. System.ArgumentNullException: значение не может быть нулевым.

Newtonsoft.Json.JsonConvert.PopulateObject(jsonString, errorDTO);

Пожалуйста, дайте мне знать, в чем проблема. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

1 Ответ

0 голосов
/ 16 января 2019

Ваша основная проблема в том, что вы объявили ErrorDTO как IEnumerator, IEnumerable, то есть нетипизированное, не универсальное перечислимое. Json.NET интерпретирует такой объект как нетипизированная коллекция только для чтения , поэтому при попытке ее заполнения вы получите исключение:

System.ArgumentNullException: Value cannot be null.
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at Newtonsoft.Json.Serialization.JsonArrayContract.CreateWrapper(Object list)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
   at Newtonsoft.Json.JsonSerializer.PopulateInternal(JsonReader reader, Object target)
   at Newtonsoft.Json.JsonConvert.PopulateObject(String value, Object target, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.PopulateObject(String value, Object target)

Сообщение об исключении бесполезно и вводит в заблуждение, но настоящая причина в том, что Json.NET не имеет возможности узнать ни целевой тип элементов коллекции, к которым следует десериализоваться, ни метод добавления их после десериализации для любая нетипизированная коллекция только для чтения.

Обычным способом решения такой проблемы было бы объявить ErrorDTO как ICollection<ErrorObj> и реализовать необходимые универсальные методы, информируя тем самым Json.NET как о типе элемента, так и о Add() метод, но, к сожалению, вы заявляете

Я не могу изменить их [классы].

Таким образом, самый простой обходной путь - заполнить базовый список:

Newtonsoft.Json.JsonConvert.PopulateObject(json, resultDTO.ErrorList);

Демонстрационная скрипка здесь .

...