类型是接口或抽象类,不能实例化

本文关键字:不能 实例化 抽象类 接口 类型 | 更新日期: 2023-09-27 18:11:59

我先说一下,我知道问题是什么,我只是不知道如何解决它。我正在与一个. net SOA数据层进行通信,该数据层以JSON形式返回数据。其中一个方法返回一个对象,其中包含多个集合。对象基本上是这样的:

{
  "Name":"foo",
  "widgetCollection":[{"name","foo"}, {"name","foo"},],
  "cogCollection": [{"name","foo"}, {"childCogs",<<new collection>>},],
}

表示这个对象的类是这样的:

public class SuperWidget : IWidget
{
    public string Name { get; set; }
    public ICollection<IWidget> WidgetCollection { get; set; }
    public ICollection<ICog> CogCollection { get; set; }
    public SuperWidget()
    {
    }
    [JsonConstructor]
    public SuperWidget(IEnumerable<Widget> widgets, IEnumerable<Cog> cogs)
    {
        WidgetCollection = new Collection<IWidget>();
        CogCollection = new Collection<ICog>();
        foreach (var w in widgets)
        {
            WidgetCollection.Add(w);
        }
        foreach (var c in cogs)
        {
            CogCollection.Add(c);
        }
    }
}

在cogCollection添加子集合之前,这个构造函数工作得很好,现在我得到了上面的错误。一个具体的齿轮类是这样的:

[Serializable]
public class Cog : ICog
{
    public string name { get; set; }
    public ICollection<ICog> childCogs { get; set; }        
}  

我不想将集合更改为具体类型,因为我正在使用IoC。因为我正在使用IoC,我真的很想摆脱需要JsonConstructors接受具体参数,但我还没有找到一种方法来做到这一点。任何建议将非常感激!

更新:

Yuval Itzchakov关于这个问题可能是重复的建议在某种程度上是正确的(看起来)。在引用的帖子中,页面下方的一个答案提供了与这里提供的相同的解决方案。我没有注意到这个答案,因为OP的问题和我在这里的问题不同。我的错误。

——我的解决方案 --------

正如我所说:马特的解决方案花了一点功夫,但我找到了一些适合我的东西。我不喜欢他最初的解决方案的一点是,像这样的行:

 return objectType == typeof(ICog); 

按照这种模式,您需要为通过网络接收的每个抽象类型提供一个JsonConverter。这在我的情况下是不太理想的,所以我创建了一个通用的JsonConverter:

public class GenericJsonConverter<T>: JsonConverter, IBaseJsonConverter<T>
{
    private readonly IUnityContainer Container;
    public GenericJsonConverter(IUnityContainer container)
    {
        Container = container;
    }
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(T);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader);
        var result = Container.Resolve<T>();
        serializer.Populate(target.CreateReader(), result);
        return result;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

然后在我反序列化数据之前,我做这样的事情:

 var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
 settings.Converters.Add((JsonConverter)Container.Resolve<IBaseJsonConverter<ICog>>());

Protip:如果你使用Resharper, (JsonConverter)会在这种情况下给你一个可疑的强制转换警告。

希望以后有人会发现这有用!

类型是接口或抽象类,不能实例化

您需要为Json提供一个自定义序列化器。网告诉它如何处理孩子的齿轮。例如:

var settings = new JsonSerializerSettings();
settings.Converters.Add(new CogConverter());

您的CogConverter需要从JsonConverter继承,并指定它CanConvert您的ICog接口。也许可以这样写:

public class CogConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ICog);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, typeof(Cog));
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}
在这种情况下,我建议用IoC容器注册您的JsonSerializerSettings。如果序列化器不能实际负责构造Cog,你也可以考虑给CogConverter访问容器的权限;这完全取决于您的特定架构。

编辑

进一步阅读后,似乎您可能正在寻找具体如何使用为人口创建的ICog的IoC。我使用以下内容作为我的ReadJson的一部分:

var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader);
var objectType = DetermineConcreteType(target);
var result = iocContainer.Resolve(objectType);
serializer.Populate(target.CreateReader(), result);
return result;

这允许您使用任何对象并从原始JSON填充它,在DetermineConcreteType方法中使用您希望的自定义类型。

相关文章: