无法将作业对象类型转换为字典<string, EntityProperty>

Cannot convert Jobject type to a Dictionary<string, EntityProperty>

如何将 JObject 转换为 Dictionary<string, EntityProperty>。 我这样试过

data.ToObject<Dictionary<string, EntityProperty>>()

但它给我的错误是 ""将值“123”转换为类型 'Microsoft.Azure.Cosmos.Table.EntityProperty' 时出错。路径 'Version'."}""

我该怎么做? 调试时的 data 给我这个结构:

{
  "Version": "123",
  "Eest": {
    "Bulls": 1848,
    "Message": "Passed (0.325 mA < 2[0] => 'P')",
    "Credit": 0.325,
    "Read": 0.14,
    "SBin": "P"
  },
  "GenericTests": [],
  "HostVersion": "Test",
  "RawSampleIDData": [
    1,
    3,
    2,
    4
  ]
}

您不能将问题中显示的 JSON 对象反序列化为 Dictionary<string, EntityProperty>,即使 custom JsonConverter. This is because EntityProperty is a Class for storing information about a single property in an entity in a table. As such, it can capture a variety of .Net primitives including:

  • byte []
  • bool
  • DateTime.
  • doubleintlong.
  • string

但是,您的根 JSON 对象的值包括嵌套数组 ("RawSampleIDData") 和对象 ("Eest")。因此,它不能反序列化为 EntityProperty 基元的字典。您将需要采用不同的数据模型来反序列化 JSON.

相关的,见:

  • insert complex objects to azure table with TableServiceEntity.

如果您的对象值完全是 JSON 原语,您可以引入以下转换器:

public class EntityPropertyConverter : JsonConverter<EntityProperty>
{
    public override void WriteJson(JsonWriter writer, EntityProperty value, JsonSerializer serializer) =>
        serializer.Serialize(writer, value.PropertyAsObject);

    public override EntityProperty ReadJson(JsonReader reader, Type objectType, EntityProperty existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        switch (reader.MoveToContentAndAssert().TokenType)
        {
            case JsonToken.Null:
                return null;
            case JsonToken.Integer:
                if (reader.Value is int i)
                    return new EntityProperty(i);
                else if (reader.Value is long l)
                    return new EntityProperty(l);
                // BigInteger not supported.
                break;
            case JsonToken.Float:
                if (reader.Value is double d)
                    return new EntityProperty(d);
                else if (reader.Value is decimal m)
                    return new EntityProperty((double)m);
                break;
            case JsonToken.String:
                return new EntityProperty((string)reader.Value);
            case JsonToken.Boolean:
                return new EntityProperty((bool)reader.Value);
            case JsonToken.Date:
                if (reader.Value is DateTime dt)
                    return new EntityProperty(dt);
                else if (reader.Value is DateTimeOffset dto)
                    return new EntityProperty(dto);
                break;
            case JsonToken.Bytes:
                if (reader.Value is byte [] a)
                    return new EntityProperty(a);
                else if (reader.Value is Guid g)
                    return new EntityProperty(g);
                break;
        }
        throw new JsonSerializationException(string.Format("Cannot convert value {0} to {1}", reader.TokenType, nameof(EntityProperty)));
    }       
}

public static partial class JsonExtensions
{
    public static JsonReader MoveToContentAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (reader.TokenType == JsonToken.None)       // Skip past beginning of stream.
            reader.ReadAndAssert();
        while (reader.TokenType == JsonToken.Comment) // Skip past comments.
            reader.ReadAndAssert();
        return reader;
    }

    public static JsonReader ReadAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (!reader.Read())
            throw new JsonReaderException("Unexpected end of JSON stream.");
        return reader;
    }
}

然后做:

var settings = new JsonSerializerSettings
{
    Converters = { new EntityPropertyConverter() },
};
var dict = data.ToObject<Dictionary<string, EntityProperty>>(JsonSerializer.CreateDefault(settings));

演示 fiddle here.

更新

使用上述转换器,将任意 JObject 反序列化为 Dictionary<string, EntityProperty> 的一种选择是将对象展平为由每个原始值的 path 键控的字典,像这样:

var settings = new JsonSerializerSettings
{
    Converters = { new EntityPropertyConverter() },
};
var serializer = JsonSerializer.CreateDefault(settings);
var dict = data.Descendants().OfType<JValue>().ToDictionary(v => v.Path, v => v.ToObject<EntityProperty>(serializer));

对于问题中的JSON,结果是

{
  "Version": "123",
  "Eest.Bulls": 1848,
  "Eest.Message": "Passed (0.325 mA < 2[0] => 'P')",
  "Eest.Credit": 0.325,
  "Eest.Read": 0.14,
  "Eest.SBin": "P",
  "HostVersion": "Test",
  "RawSampleIDData[0]": 1,
  "RawSampleIDData[1]": 3,
  "RawSampleIDData[2]": 2,
  "RawSampleIDData[3]": 4
}

演示 fiddle #2 here.