我如何判断是否曾在 .NET 的反序列化 JSON 对象中定义过键?

How can I tell if a key was ever defined in a deserialized JSON object in .NET?

我正在使用 C#/.NET 4.5 将 JSON 对象反序列化为本机 .NET 类型。 JSON 看起来像:

{
    id: 841,
    runningTime: 33.8643736,
    title: "Test title"
}

...它反序列化后的 class 看起来像:

public class Slide
{
    public double runningTime
    {
        get;
        set;
    }

    public string title
    {
        get;
        set;
    }

    public int id
    {
        get;
        set;
    }
}

...使用此代码对其进行反序列化:

// given serializer is an instance of JavaScriptSerializer
var slide = serializer.Deserialize<Slide>(json);

这很好用,我可以像直接读取 JSON.

一样读取对象的属性

但是,如果 title 是 JSON 中的可选键呢?我可以在反序列化后检查它是否为 null,但这并不完美,因为 title 可以在 JSON 本身中合法地设置为 null,我需要知道密钥本身是否已定义。为 title 使用一些占位符值,例如 "UNDEFINED" 也很老套。

所以,如果我使用 JavaScriptDeserializer 来反序列化 JSON,我如何判断一个键是否首先在 JSON 中定义与显式设置为无效?

无需过多更改其余代码,您就可以更改定义属性的方式。 Nullable<T> 为辅助结构提供了一个很好的模型,但仅适用于值类型。一个也适用于引用类型的版本很容易制作,除了没有特殊的编译器和运行时支持(这里不需要):

public struct Optional<T>
{
  private readonly bool hasValue;
  private readonly T value;
  public Optional(T value) {
    this.hasValue = true;
    this.value = value;
  }
  public bool HasValue {
    get { return hasValue; }
  }
  public T Value {
    get {
      if (!hasValue)
        throw new InvalidOperationException();
      return value;
    }
  }
  public T GetValueOrDefault() {
    return value;
  }
  public T GetValueOrDefault(T @default) {
    return hasValue ? value : @default;
  }
}

根据需要添加方法。

有了这个之后,您可以更改 class 以将您的属性标记为可选:

public class Slide
{
  private Optional<double> _runningTime;
  private Optional<string> _title;
  private Optional<int> _id;

  public double runningTime
  {
    get { return _runningTime.GetValueOrDefault(); }
    set { _runningTime = new Optional<double>(value); }
  }

  public string title
  {
    get { return _title.GetValueOrDefault(); }
    set { _title = new Optional<string>(value); }
  }

  public int id
  {
    get { return _id.GetValueOrDefault(); }
    set { _id = new Optional<int>(value);
  }
}

然后您可以确定 属性 setter 是否曾被调用,并添加对显式取消设置属性的支持:

  public bool IsIdSet() {
    return _id.HasValue;
  }
  public void ResetId() {
    _id = default(Optional<int>);
  }

我认为检查 null 是不够的,因为 JSON 可能包含 null。所以你可以这样做:

public class Slide
{
    public bool HasTitle { get; private set; }

    public double runningTime
    {
        get;
        set;
    }

    private string _title;

    public string title
    {
        get { return _title;  }
        set { _title = value; HasTitle = true; }
    }

    public int id
    {
        get;
        set;
    }
}

现在检查 "HasTitle" 看看标题 属性 是否曾经设置过。