类型是接口或抽象类,无法实例化 [英] Type is an interface or abstract class and cannot be instantiated

查看:118
本文介绍了类型是接口或抽象类,无法实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我要说的是我知道问题是什么,我只是不知道如何解决它.我正在与.NET SOA数据层通信,该数据层将数据作为JSON返回.一种这样的方法返回一个对象,其中包含多个集合.该对象基本上如下所示:

I will preface this by saying that I know what the problem is, I just don't know how to solve it. I am communicating with a .NET SOA data layer that returns data as JSON. One such method returns an object that has several collections within it. The object basically looks like this:

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

我代表该对象的类如下:

My class that represents this object looks like this:

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添加一个子集合之前,此构造函数运行良好,现在出现上述错误.一个具体的齿轮类如下:

This constructor worked fine until the cogCollection added a child collection, and now I am getting the above error. A concrete cog class looks like this:

[Serializable]
public class Cog : ICog
{
    public string name { get; set; }

    public ICollection<ICog> childCogs { get; set; }        
}  

我不想将集合更改为具体类型,因为我正在使用IoC.因为我使用的是IoC,所以我真的很想摆脱使用具体参数的JsonConstructors的需要,但是我还没有想办法做到这一点.任何建议将不胜感激!

I don't want to change the collection to a concrete type because I am using IoC. Because I am using IoC I would really like to get away from the need to have the JsonConstructors that take concrete parameters, but I haven't figured out a way to do that. Any advice would be greatly appreciated!

更新:

尤瓦尔·伊茨恰科夫(Yuval Itzchakov)提出的这个问题可能是重复的建议似乎是正确的.在引用的帖子中,页面下方的答案之一提供了此处提供的相同解决方案.我没有注意到该答案,因为OP的问题与我在这里提出的问题有所不同.我的错.

Yuval Itzchakov's suggestion that this question is probably a duplicate is somewhat true (it seems). In the post referenced, one of the answers down the page provides same solution that was provided here. I didn't notice that answer, since the OP's question was different then the one I had here. My mistake.

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

-------my solution--------

正如我所说:Matt的解决方案花费了一些时间,但我得到了一些适合我的设置.关于他最初的解决方案,我不喜欢的一件事就是这样的代码:

As I said: Matt's solution took a little bit of work but I got something setup that works for me. The one thing I didn't like about his initial solution, were lines like these:

 return objectType == typeof(ICog); 

按照此模式,您需要为通过导线接收的每种抽象类型都具有一个JsonConverter.在我的情况下,这并不理想,因此我创建了一个通用的JsonConverter,如下所示:

Following this pattern you would need to have a JsonConverter for every abstract type that you receive over the wire. This is less than ideal in my situation, so I created a generic JsonConverter as such:

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);
    }
}

然后在反序列化数据之前,我会执行以下操作:

Then just before I deserialize my data, I do something like this:

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

提示:如果您使用Resharper,在这种情况下(JsonConverter)将向您提供可疑的投射警告.

Protip: If you use Resharper, (JsonConverter) will give you a suspicious cast warning in this scenario.

希望其他人会在将来找到有用的东西!

Hopefully someone else finds this useful down the road!

推荐答案

您需要为Json.Net提供一个自定义序列化程序,以告诉它如何处理子齿轮.例如:

You'll need to provide a custom serializer to Json.Net to tell it how to handle the child cogs. For example:

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

您的CogConverter将需要从JsonConverter继承,并将其指定为CanConvert您的ICog接口.也许是这样的:

Your CogConverter will need to inherit from JsonConverter and specify that it CanConvert your ICog interface. Perhaps something along the lines of:

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访问该容器的权限.一切都取决于您的特定体系结构.

I'd recommend registering your JsonSerializerSettings with your IoC container in that case. You may want to consider giving CogConverter access to the container, too, if the serializer can't be responsible for actually constructing the Cog itself; that all depends on your particular architecture.

修改

在进一步阅读后,您似乎似乎正在寻找如何专门使用IoC创建的ICog进行人口统计的方法.我将以下内容用作ReadJson的一部分:

Upon further reading, it seems like you might be looking for specifically how to use the IoC created ICog for population. I'm using the following as part of my 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;

这允许您使用ANY对象,并根据需要在DetermineConcreteType方法中使用自定义类型,将其从原始JSON填充.

This allows you to use ANY object and populate it from the original JSON, using custom types as you wish inside your DetermineConcreteType method.

这篇关于类型是接口或抽象类,无法实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆