【问题标题】:How to cast an instantiated concurrentdictionary to IDictionary如何将实例化的并发字典转换为 IDictionary
【发布时间】:2018-02-05 15:43:48
【问题描述】:

我有一个对象,其中包含几个字典类型,这些字典类型被序列化为 Json

public class Foo
{
    public Dictionary<string, bool> SomeDict {get;set;}
    public ConcurrentDictionary<string, complextype> SomeconcurrentDict {Get;set;}
}

现在this answer explains 我需要一个转换器来这样做。使用该答案作为示例,我创建了以下内容,以便它可以应用于字典和并发字典。

public class JsonDictionaryConverter<k, v> : CustomCreationConverter<IDictionary<k, v>>
{
    public override IDictionary<k, v> Create(Type objectType)
        => Activator.CreateInstance(objectType) as IDictionary<k, v>;

    // in addition to handling IDictionary<string, object>, we want to handle the deserialization of dict value, which is of type object
    public override bool CanConvert(Type objectType) => objectType == typeof(object) || base.CanConvert(objectType);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject || reader.TokenType == JsonToken.Null)
            return base.ReadJson(reader, objectType, existingValue, serializer);

        // if the next token is not an object
        // then fall back on standard deserializer (strings, numbers etc.)
        return serializer.Deserialize(reader);
    }
}

但是,由于 as 转换为 IDictionary&lt;k,v&gt; 失败,并导致 NULL,而不是 IDictionary,我遇到了空引用异常。

然而,激活器创建对象是一个 ConcurrentDictionary,具有匹配的 K 和 V 值,这让我认为应该可以将其转换为 as IDictionary&lt;k,v&gt;

那么如何将激活器实例化对象转换为 IDictionary&lt;k,v&gt;

应用属性后,类如下所示。

public class Foo
{
    [JsonConverter(typeof(JsonDictionaryConverter<string,bool>))]
    public Dictionary<string, bool> SomeDict {get;set;}

    [JsonConverter(typeof(JsonDictionaryConverter<string,complextype>))]
    public ConcurrentDictionary<string, complextype> SomeconcurrentDict {Get;set;}
}

.netfiddler 上的简化测试场景似乎可以很好地运行代码,从而生成精美的对象。

在我的本地机器上,但是使用几乎相同的对象,这会导致空引用异常由于强制转换导致 NULL

public class Settings 
{
    [JsonConverter(typeof(JsonDictionaryConverter<string,string>))]
    public ConcurrentDictionary<string, string> Prefix { get; set; }

    [JsonConverter(typeof(JsonDictionaryConverter<string,bool>))]
    public ConcurrentDictionary<string, bool> AllowMentions { get; set; }

    public BotSettings()
    {
        Prefix = new ConcurrentDictionary<string, string>();
        AllowMentions = new ConcurrentDictionary<string, bool>();
    }

    public Settings LoadSettings()
    {
        Settings settings = null;

 // Temporary hardcoded json, for debug purposes
        if (File.Exists(file))
            settings = Serializer.DeserializeJson<BotSettings>("{\"Prefix\":{\"164427220197179403\":\".\",\"342638529622310925\":\".\"},\"AllowMentions\":{\"164427220197179403\":true,\"342638529622310925\":true}}");//string.Join(" ", ReadLines(file)));

        return settings;
    }
}

【问题讨论】:

  • 您确定kv 是正确的类型(它们与您类中的定义匹配)吗?
  • 你能发布你正在测试的完整的小代码吗?
  • 问题是,异常与您发布的代码无关。我们不知道在哪里以及如何使用这个类。课堂作业测试。
  • 如果Create 返回null 是错误的,则将as 的使用更改为显式转换,即(IDictionary&lt;k, v&gt;)Activator.CreateInstance(objectType)。这也将简化调试过程。

标签: c# casting


【解决方案1】:

原来不是Create 导致了异常。但是调用 Create 的方法却是:

return base.ReadJson(reader, objectType, existingValue, serializer);

这似乎是旧版本 NewtonSoft 中的一个问题,通过升级到最新版本 10.0.3 得到了解决。这也是 Fiddle 确实可以正常工作的原因,因为它确实使用了较新的版本,而不是我自己的项目。

【讨论】:

    猜你喜欢
    • 2021-08-06
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多