Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用引用将Json.NET反序列化为动态对象_C#_Dynamic_Json.net - Fatal编程技术网

C# 使用引用将Json.NET反序列化为动态对象

C# 使用引用将Json.NET反序列化为动态对象,c#,dynamic,json.net,C#,Dynamic,Json.net,如何让Json.NET反序列化为动态对象,但仍然执行引用解析? dynamic d=JsonConvert.DeserializeObject(…)就像 dynamic d=JsonConvert.DeserializeObject(…)返回一个动态对象,但它们不解析$ref和$id部分。(例如,ExpandoObject eo将只具有eo[“$ref”]=“…”,并且不具有它应该具有的属性,因为它与$id-对象不同) 我发现我需要契约解析程序解析为动态契约-只有当我使用自定义的契约解析程序显式

如何让Json.NET反序列化为动态对象,但仍然执行引用解析?
dynamic d=JsonConvert.DeserializeObject(…)
就像
dynamic d=JsonConvert.DeserializeObject(…)
返回一个动态对象,但它们不解析
$ref
$id
部分。(例如,
ExpandoObject eo
将只具有
eo[“$ref”]=“…”
,并且不具有它应该具有的属性,因为它与
$id
-对象不同)

我发现我需要契约解析程序解析为动态契约-只有当我使用自定义的契约解析程序显式地告诉Json.NET时,
ExpandoObject
才会解析为动态契约

但是,
ExpandoObject
似乎是用它自己的转换器解析的,它再次失败

我尝试了一个从
IDynamicMetaObjectProvider
继承的自定义类,它导致了一个无限循环,似乎不是正确的选择。实际上,我希望一些简单的解决方案能够使
ExpandoObject
具有参考分辨率


有什么帮助吗?

由于Json.NET是开源的,并且是MIT许可证,最简单的解决方案可能是根据您的需要调整它:

/// <summary>
/// Converts an ExpandoObject to and from JSON, handling object references.
/// </summary>
public class ObjectReferenceExpandoObjectConverter : JsonConverter
{
    // Adapted from https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // can write is set to false
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return ReadValue(serializer, reader);
    }

    private object ReadValue(JsonSerializer serializer, JsonReader reader)
    {
        while (reader.TokenType == JsonToken.Comment)
        {
            if (!reader.Read())
                throw reader.CreateException("Unexpected end when reading ExpandoObject.");
        }

        switch (reader.TokenType)
        {
            case JsonToken.StartObject:
                return ReadObject(serializer, reader);
            case JsonToken.StartArray:
                return ReadList(serializer, reader);
            default:
                if (JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
                    return reader.Value;
                throw reader.CreateException("Unexpected token when converting ExpandoObject");
        }
    }

    private object ReadList(JsonSerializer serializer, JsonReader reader)
    {
        IList<object> list = new List<object>();

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.Comment:
                    break;
                default:
                    object v = ReadValue(serializer, reader);
                    list.Add(v);
                    break;
                case JsonToken.EndArray:
                    return list;
            }
        }

        throw reader.CreateException("Unexpected end when reading ExpandoObject.");
    }

    private object ReadObject(JsonSerializer serializer, JsonReader reader)
    {
        IDictionary<string, object> expandoObject = null;
        object referenceObject = null;

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.PropertyName:
                    string propertyName = reader.Value.ToString();
                    if (!reader.Read())
                        throw new InvalidOperationException("Unexpected end when reading ExpandoObject.");
                    object v = ReadValue(serializer, reader);
                    if (propertyName == "$ref")
                    {
                        var id = (v == null ? null : Convert.ToString(v, CultureInfo.InvariantCulture));
                        referenceObject = serializer.ReferenceResolver.ResolveReference(serializer, id);
                    }
                    else if (propertyName == "$id")
                    {
                        var id = (v == null ? null : Convert.ToString(v, CultureInfo.InvariantCulture));
                        serializer.ReferenceResolver.AddReference(serializer, id, (expandoObject ?? (expandoObject = new ExpandoObject())));
                    }
                    else
                    {
                        (expandoObject ?? (expandoObject = new ExpandoObject()))[propertyName] = v;
                    }
                    break;
                case JsonToken.Comment:
                    break;
                case JsonToken.EndObject:
                    if (referenceObject != null && expandoObject != null)
                        throw reader.CreateException("ExpandoObject contained both $ref and real data");
                    return referenceObject ?? expandoObject;
            }
        }

        throw reader.CreateException("Unexpected end when reading ExpandoObject.");
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(ExpandoObject));
    }

    public override bool CanWrite
    {
        get { return false; }
    }
}

public static class JsonTokenUtils
{
    // Adapted from https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/JsonTokenUtils.cs
    public static bool IsPrimitiveToken(this JsonToken token)
    {
        switch (token)
        {
            case JsonToken.Integer:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Undefined:
            case JsonToken.Null:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return true;
            default:
                return false;
        }
    }
}

public static class JsonReaderExtensions
{
    public static JsonSerializationException CreateException(this JsonReader reader, string format, params object[] args)
    {
        // Adapted from https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/JsonPosition.cs

        var lineInfo = reader as IJsonLineInfo;
        var path = (reader == null ? null : reader.Path);
        var message = string.Format(CultureInfo.InvariantCulture, format, args);
        if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
        {
            message = message.Trim();
            if (!message.EndsWith(".", StringComparison.Ordinal))
                message += ".";
            message += " ";
        }
        message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path);
        if (lineInfo != null && lineInfo.HasLineInfo())
            message += string.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition);
        message += ".";

        return new JsonSerializationException(message);
    }
}
//
///将ExpandooObject转换为JSON和JSON,处理对象引用。
/// 
公共类对象引用ExpandoobjectConverter:JsonConverter
{
//改编自https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
//can write设置为false
抛出新的NotImplementedException();
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
返回ReadValue(序列化程序、读取器);
}
私有对象ReadValue(JsonSerializer序列化程序、JsonReader阅读器)
{
while(reader.TokenType==JsonToken.Comment)
{
如果(!reader.Read())
抛出reader.CreateException(“读取ExpandooObject时意外结束”);
}
开关(reader.TokenType)
{
案例JsonToken.StartObject:
返回ReadObject(序列化程序、读取器);
案例JsonToken.StartArray:
返回ReadList(序列化程序、读取器);
违约:
if(JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
返回reader.Value;
抛出reader.CreateException(“转换ExpandooObject时出现意外标记”);
}
}
私有对象读取列表(JsonSerializer序列化程序、JsonReader阅读器)
{
IList list=新列表();
while(reader.Read())
{
开关(reader.TokenType)
{
案例JsonToken。评论:
打破
违约:
对象v=读取值(序列化程序、读取器);
增加(五)项;
打破
案例JsonToken.EndArray:
退货清单;
}
}
抛出reader.CreateException(“读取ExpandooObject时意外结束”);
}
私有对象ReadObject(JsonSerializer序列化程序、JsonReader阅读器)
{
IDictionary expandoObject=null;
对象referenceObject=null;
while(reader.Read())
{
开关(reader.TokenType)
{
案例JsonToken.PropertyName:
string propertyName=reader.Value.ToString();
如果(!reader.Read())
抛出新的InvalidOperationException(“读取ExpandoObject时意外结束”);
对象v=读取值(序列化程序、读取器);
如果(propertyName==“$ref”)
{
var id=(v==null?null:Convert.ToString(v,CultureInfo.InvariantCulture));
referenceObject=serializer.ReferenceResolver.ResolveReference(序列化程序,id);
}
else if(propertyName==“$id”)
{
var id=(v==null?null:Convert.ToString(v,CultureInfo.InvariantCulture));
serializer.referencesolver.AddReference(序列化程序,id,(expandoObject??(expandoObject=newexpandoobject());
}
其他的
{
(expandoObject???(expandoObject=newexpandoobject())[propertyName]=v;
}
打破
案例JsonToken。评论:
打破
案例JsonToken.EndObject:
if(referenceObject!=null&&expandooobject!=null)
抛出reader.CreateException(“ExpandooObject同时包含$ref和real数据”);
返回referenceObject??expandooobject;
}
}
抛出reader.CreateException(“读取ExpandooObject时意外结束”);
}
公共覆盖布尔CanConvert(类型objectType)
{
返回(objectType==typeof(expandooobject));
}
公共覆盖布尔可写
{
获取{return false;}
}
}
公共静态类JsonTokenUtils
{
//改编自https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/JsonTokenUtils.cs
公共静态布尔IsPrimitiveToken(此JsonToken令牌)
{
交换机(令牌)
{
案例JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
案例JsonToken.Boolean:
案例JsonToken。未定义:
案例JsonToken.Null:
案例JsonToken。日期:
案例JsonToken.Bytes:
返回true;
违约:
        var settings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ReferenceLoopHandling = ReferenceLoopHandling.Serialize };
        settings.Converters.Add(new ObjectReferenceExpandoObjectConverter());
        dynamic d = JsonConvert.DeserializeObject<ExpandoObject>(json, settings);
    private static void Reffing(this IDictionary<string, object> current, Action<object> exchange,IDictionary<string, object> refdic)
    {
        object value;
        if(current.TryGetValue("$ref", out value))
        {
            if(!refdic.TryGetValue((string) value, out value))
                throw new Exception("ref not found ");
            if (exchange != null)
                exchange(value);
            return;
        }
        if (current.TryGetValue("$id", out value))
        {
            refdic[(string) value] = current;
        }
        foreach (var kvp in current.ToList())
        {
            if (kvp.Key.StartsWith("$"))
                continue;
            var expandoObject = kvp.Value as ExpandoObject;
            if(expandoObject != null)
                Reffing(expandoObject,o => current[kvp.Key]=o,refdic);
            var list = kvp.Value as IList<object>;
            if (list == null) continue;
            for (var i = 0; i < list.Count; i++)
            {
                var lEO = list[i] as ExpandoObject;
                if(lEO!=null)
                    Reffing(lEO,o => list[i]=o,refdic);
            }
        }
    }
        var test = JsonConvert.DeserializeObject<ExpandoObject>(...);
        var dictionary = new Dictionary<string, object>();
        Reffing(test,null,dictionary);