【问题标题】:C# JSON Deserialization : Type is an interface or abstract class and cannot be instantiatedC# JSON 反序列化:类型是接口或抽象类,不能实例化
【发布时间】:2016-05-06 10:03:02
【问题描述】:

我正在使用这个使用 APIs to communicate with the online trading platform Poloniex 的 C# 项目。

此代码应该在钱包中获取余额:

var x = await polo_client.Wallet.GetBalancesAsync();

虽然这段代码给出了这个错误:

获取钱包时出错:无法创建类型为 Jojatekok.PoloniexAPI.WalletTools.IBalance 的实例。
类型是接口或抽象类,不能实例化。
路径 '1CR.available',第 1 行,位置 20。

在 Helper.cs 中:

[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
internal static T DeserializeObject<T>(this JsonSerializer serializer, string value)
{ 
    using (var stringReader = new StringReader(value))
    {
        using (var jsonTextReader = new JsonTextReader(stringReader))
        {
            return (T)serializer.Deserialize(jsonTextReader, typeof(T));
        }
    } 
}

调用它的代码是:

public T GetData<T>(string command, params object[] parameters)
{
    var relativeUrl = CreateRelativeUrl(command, parameters);
    var jsonString = QueryString(relativeUrl);
    var output = JsonSerializer.DeserializeObject<T>(jsonString);
    return output;
}

谁能告诉我为什么反序列化这个 JSON 响应时出错?

响应是 JSON,这里是它的一个示例:

{
"1CR":{"available":"0.00000000","onOrders":"0.00000000","btcValue":"0.00000000"},
"ABY":{"available":"0.00000000","onOrders":"0.00000000","btcValue":"0.00000000"}
}

【问题讨论】:

  • 你能添加调用你的通用反序列化函数的代码吗?

标签: c# json json-deserialization


【解决方案1】:

JSON 与否,错误是自描述的。您不能实例化接口或抽象类。它们只是它们所代表的功能或对象结构的蓝图。

例如,你不能这样做:

var something = new ISomething();

但是,你可以这样做:

ISomething something = new Something();

您所需要的只是该接口的一些具体实现。比如:

public JsonReceived : IBalance
{
// rest of the implementation
}

或者可能已经由第三方提供,请查看他们的 SDK 文档。

【讨论】:

  • 我只是不习惯泛型,一年多没有用 C# 编程,所以我仍然掌握它们的窍门。如果您查看描述中链接中的示例代码,您可能会很快弄清楚。 ApiWebClient.cs是调用代码,Helper.cs是反序列化代码
  • 查看 github,我可以看到他们有 IBalance 作为 Balance 的具体实现。因此,只需在调用代码中将 IBalance 替换为 Balance。
  • 我使用的是这个来调用他们的代码:var x = await polo_client.Wallet.GetBalancesAsync();
  • 那么他们的代码可能会出现问题。 private IDictionary GetBalances() 应该是 private IDictionary GetBalances()
【解决方案2】:

这就是我为使其正常工作所做的工作。感谢 Guru.com 的 Chris 完成这项工作。很棒的家伙,而且价格也很好。你可以在这里找到他:http://www.guru.com/freelancers/deatc

private IDictionary<string, IBalance> GetBalances()
{
    var postData = new Dictionary<string, object>();
    var data = PostData<IDictionary<string, Balance>>("returnCompleteBalances", postData);
    var returnData = new Dictionary<string, IBalance>();

    foreach (string key in data.Keys)
    {
        returnData.Add(key, data[key]);
    }

    return returnData;
}

【讨论】:

    【解决方案3】:

    由于对象的反序列化导致的错误,该对象在内部创建了一个 Jobject 并将其转换为输入 Generic,在上述情况下,由于我们无法创建 Interface 的对象,因此会引发错误, 我们可以根据您在GitHub上发布的解决方案通过以下方式实现

  • 添加一个哈希表作为 PostData 方法的通用输入
  • 将您的 wallet.cs 更改为 前任:
    IBalance CreateFactory(string typeOfBalance, string jsonString)
            {
                IBalance balance = null;
                switch (typeOfBalance)
                {
                    case "balanceClassIdentification":
                        balance = new Balance();
                        balance = Newtonsoft.Json.JsonConvert.DeserializeObject<Balance>(jsonString);
                        break;
                    case "":
                    // write logic if Ibalance interface implemented in any childClass ex: class stockBalance: IBalance , then balance = new StockBalance();balance = Newtonsoft.Json.JsonConvert.DeserializeObject<stockBalance>(jsonString);
                    default:
                        balance = new Balance();
                        balance = Newtonsoft.Json.JsonConvert.DeserializeObject<Balance>(jsonString);
                        break;
                }
                return balance;
            }
            private IDictionary<string, IBalance> GetBalances()
            {
                IDictionary<string, IBalance> data = null;
                var postData = new Dictionary<string, object>();
                //var data = PostData<IDictionary<string, object>>("returnCompleteBalances", postData);
    
                Hashtable output = PostData<Hashtable>("returnCompleteBalances", postData);
                if (output.Count > 0)
                {
    
                    data = new Dictionary<string, IBalance>();
                }
                foreach (string jsonObjKey in output.Keys)
                {
                    IBalance balace = CreateFactoty("balanceClassIdentification", output[jsonObjKey].ToString()); // this "balanceClassIdentification" just used as a string but we can add the condition in createFactory according to the type of object that wallet
    
                    data.Add(jsonObjKey, balace);
                }
                return data;
            }
    

  • 创建另一个实现 Ibalance 的中间类
  • 喜欢
    public class BalanceBase: IBalace
     {
     } 
    

    需要更改平衡类

     public Balance : BalanceBase
        {
        }
    

  • 如果没有为 IBalance 实现除 balance 之外的其他类
  • 您可以直接使用 GetBalance() 方法的返回类型 作为字典 并更改实施
     private IDictionary<string, Balance> GetBalances()
            {
    
                var postData = new Dictionary<string, object>();
                var data = PostData<IDictionary<string, Balance>>("returnCompleteBalances", postData);
    
                return data;
            }
    

    【讨论】:

    • 感谢您的解决方案,尽管我得到了一个对我有用的更简单的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多