簡體   English   中英

類型是接口或抽象類,不能被實例化

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

我先說我知道問題是什么,我只是不知道如何解決它。 我正在與以 JSON 形式返回數據的 .NET SOA 數據層進行通信。 一個這樣的方法返回一個對象,其中包含多個集合。 該對象基本上如下所示:

{
  "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 添加了一個子集合,現在我收到了上述錯誤。 具體的 cog 類如下所示:

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

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

我不想將集合更改為具體類型,因為我使用的是 IoC。 因為我正在使用 IoC,所以我真的很想擺脫對采用具體參數的 JsonConstructors 的需求,但我還沒有想出一種方法來做到這一點。 任何建議將不勝感激!

更新:

尤瓦爾·伊茨查科夫 (Yuval Itzchakov) 認為這個問題可能是重復的,這在某種程度上是正確的(似乎)。 在引用的帖子中,頁面下方的答案之一提供了與此處提供的相同的解決方案。 我沒有注意到那個答案,因為 OP 的問題與我在這里提出的問題不同。 我的錯。

-------我的解決辦法------

正如我所說:Matt 的解決方案花了一點時間,但我得到了一些適合我的設置。 我不喜歡他最初的解決方案的一件事是這樣的行:

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

提示:如果你使用 Resharper,(JsonConverter) 會在這種情況下給你一個可疑的轉換警告。

希望其他人發現這很有用!

您需要向 Json.Net 提供自定義序列化程序,以告訴它如何處理子齒輪。 例如:

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

在這種情況下,我建議將您的JsonSerializerSettings注冊到您的 IoC 容器。 如果序列化程序不能負責實際構建Cog本身,您可能還需要考慮讓CogConverter訪問容器; 這一切都取決於您的特定架構。

編輯

進一步閱讀后,您似乎正在尋找具體如何使用 IoC 創建的ICog進行人口。 我使用以下作為我的 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混凝土類型方法中使用您希望的自定義​​類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM