简体   繁体   English

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

[英]Type is an interface or abstract class and cannot be instantiated

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.我正在与以 JSON 形式返回数据的 .NET SOA 数据层进行通信。 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);
        }
    }
}

This constructor worked fine until the cogCollection added a child collection, and now I am getting the above error.这个构造函数工作正常,直到 cogCollection 添加了一个子集合,现在我收到了上述错误。 A concrete cog class looks like this:具体的 cog 类如下所示:

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

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

I don't want to change the collection to a concrete type because I am using IoC.我不想将集合更改为具体类型,因为我使用的是 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.因为我正在使用 IoC,所以我真的很想摆脱对采用具体参数的 JsonConstructors 的需求,但我还没有想出一种方法来做到这一点。 Any advice would be greatly appreciated!任何建议将不胜感激!

Update:更新:

Yuval Itzchakov's suggestion that this question is probably a duplicate is somewhat true (it seems).尤瓦尔·伊茨查科夫 (Yuval Itzchakov) 认为这个问题可能是重复的,这在某种程度上是正确的(似乎)。 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.我没有注意到那个答案,因为 OP 的问题与我在这里提出的问题不同。 My mistake.我的错。

-------my solution-------- -------我的解决办法------

As I said: Matt's solution took a little bit of work but I got something setup that works for me.正如我所说:Matt 的解决方案花了一点时间,但我得到了一些适合我的设置。 The one thing I didn't like about his initial solution, were lines like these:我不喜欢他最初的解决方案的一件事是这样的行:

 return objectType == typeof(ICog); 

Following this pattern you would need to have a JsonConverter for every abstract type that you receive over the wire.遵循此模式,您需要为通过网络接收的每个抽象类型都有一个 JsonConverter。 This is less than ideal in my situation, so I created a generic JsonConverter as such:这在我的情况下不太理想,所以我创建了一个通用的 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);
    }
}

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

Protip: If you use Resharper, (JsonConverter) will give you a suspicious cast warning in this scenario.提示:如果你使用 Resharper,(JsonConverter) 会在这种情况下给你一个可疑的转换警告。

Hopefully someone else finds this useful down the road!希望其他人发现这很有用!

You'll need to provide a custom serializer to Json.Net to tell it how to handle the child cogs.您需要向 Json.Net 提供自定义序列化程序,以告诉它如何处理子齿轮。 For example:例如:

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

Your CogConverter will need to inherit from JsonConverter and specify that it CanConvert your ICog interface.您的CogConverter将需要从JsonConverter继承并指定它CanConvert您的ICog接口。 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);
    }
}

I'd recommend registering your JsonSerializerSettings with your IoC container in that case.在这种情况下,我建议将您的JsonSerializerSettings注册到您的 IoC 容器。 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;如果序列化程序不能负责实际构建Cog本身,您可能还需要考虑让CogConverter访问容器; that all depends on your particular architecture.这一切都取决于您的特定架构。

Edit编辑

Upon further reading, it seems like you might be looking for specifically how to use the IoC created ICog for population.进一步阅读后,您似乎正在寻找具体如何使用 IoC 创建的ICog进行人口。 I'm using the following as part of my ReadJson:我使用以下作为我的 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;

This allows you to use ANY object and populate it from the original JSON, using custom types as you wish inside your DetermineConcreteType method.这允许您使用任何对象并从原始 JSON 填充它,在您的DetermineConcreteType混凝土类型方法中使用您希望的自定义​​类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法创建类型的实例。 类型是接口或抽象类,不能被实例化 - Could not create an instance of type . Type is an interface or abstract class and cannot be instantiated ReadAsAsync - 错误:“Type是一个接口或抽象类,无法实例化。” - ReadAsAsync - Error : “Type is an interface or abstract class and cannot be instantiated.” C#JSON反序列化:Type是接口或抽象类,无法实例化 - C# JSON Deserialization : Type is an interface or abstract class and cannot be instantiated 为什么不能实例化抽象类和接口? - Why abstract class and interface cannot be instantiated? 类型是接口或抽象类,无法实例化。 c#发送一个包含抽象对象列表的对象 - Type is an interface or abstract class and cannot be instantiated. c# send a object with contain a list of abstract object 无法创建类型 X 的实例。类型是接口或抽象类,无法实例化 - Could not create an instance of type X. Type is an interface or abstract class and cannot be instantiated 无法使用类型创建抽象类或接口接口的实例 - Cannot create an instance of the abstract class or interface interface with type 是一个抽象类的一种接口? - is an abstract class a type of interface? 无法创建抽象类或接口的实例,但它不是抽象类,也不是接口? - Cannot create an instance of the abstract class or interface, but it is not an abstract class and it's not an interface? 为什么抽象类不能被实例化,什么是无法实例化的类的使用 - why abstract class cannot be instantiated ,what is the use of a class which cannot be instantiated
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM