【问题标题】:How to write a generic method to built a list of data with common interface?如何编写通用方法来构建具有通用接口的数据列表?
【发布时间】:2016-05-27 07:15:30
【问题描述】:

我们将使用压缩的 json 字符串在我们的系统中存储/传递配置数据。

我们在所有数据类的接口(IData)中添加了fromJson和toJson两个方法。我们已经构建了一个通用方法来将这些数据列表转换为 json,如下所示:

public static dynamic List2Json(List<IData> data)
{
  List<dynamic> json = new List<dynamic>();
  foreach(IData o in data)
  {
    json.Add(o.toJson());
  }
  return json;
}

但是构建类似的方法将 json 数组转换回列表时存在问题。我们不能为接口创建对象。 (即 IData x = new IData();)或者即使我们创建了一个基类,我们仍然不能这样做。

public void Json2List(ref List<IData> list, DynamicJsonArray json)
{
  list = new List<IData>();
  foreach(dynamic o in json)
  {
    IData x = new IData();
    x.fromJson(o);
    list.Add(x);
  }
}

我们也尝试了下面的通用方法,但仍然无法通过 T x = new T(); 创建对象

public void Json2List<T>(ref List<T> data, dynamic json) where T : IData
{
  data = new List<T>();
  foreach(dynamic o in json)
  {
    T x = new T();
    x.fromJson(o);
    data.Add(o);
  }
}

我们还考虑通过数据类的静态方法返回新实例的另一种方式。但遗憾的是,接口不支持静态方法,基类中的静态方法不能被覆盖。所以我们仍然需要该类的一个实例才能创建另一个实例。最后,我们做了一个愚蠢的方法,需要一个所需类的实例作为参数,并使用这个虚拟实例来生成列表的所有实例。

  public interface IData
  {
    IData createFromJson(dynamic json);
    dynamic toJson();
  }

  public abstract class baseData : IData
  {
    public virtual IData objectFromJson(dynamic json, baseData source)
    {
      return source.createFromJson(json);
    }
    public abstract IData createFromJson(dynamic json); 
  }

  public static void Json2List<T>(ref List<T> data, dynamic json, baseData source) where T : IData
  {
    data = new List<T>();
    foreach(dynamic o in json)
    {
      data.Add(source.objectFromJson(o, source));
    }
  }

  public class a : baseData
  {
    public override IData createFromJson(dynamic json)
    {
      a object = new a();
      // assign the value to object from json here
      return object;
    }
  }

  // in the program need to convert from json
  //
  dynamic json = ... // json object containing required data
  List<a> list = new List<a>();  
  Json2List(ref list, json, new a());  

现在它可以工作了,但它需要在调用方法时创建一个虚拟对象。

即Json2List(ref list, json, new a());在上面的例子中。真的很假,我们只需要这个实例来调用 createFromJson 方法。

请问有什么办法可以改进程序,这样就不需要用这种方式构建一个dummy object了?

【问题讨论】:

  • 你用什么来做实际的序列化? Json.Net?
  • 而且,您使用动态而不是对象是否有原因?到底什么是“动态”json?
  • 如果接口的方法返回dynamic或以dynamic作为参数,可能实现该接口的类没有任何共同点。
  • 我只是使用 System.Web.Helpers 中的 Json 类。目前主要是为了序列化,我们已经尝试序列化对象本身,但是当我们修改类定义(例如添加一些新元素)时会出现问题,它可能无法读取现有数据文件。此外,一些数据来自 json 字符串格式的 Web 服务。因此,我们在应用程序中传递数据时选择使用 Json。

标签: c#


【解决方案1】:

这应该可以通过结合泛型和 where 中的 new() 子句来实现。后者告诉编译器允许 new 泛型类型。你必须确保泛型类型有一个没有参数的构造函数。

public void Json2List<T>(...) where T : IData, new()
{
  data = new T() as IData;
  ...
}

【讨论】:

  • 非常感谢,我只是尝试修改代码,但还有另一个问题。如果 data 被定义为 T,那么 data = new T() as IData;会导致错误。但是如果数据被定义为 IData,当我尝试将它添加到列表时它会出错。我是否应该将数据定义为 IData,然后在添加到列表时添加类型转换?谢谢。
  • 非常感谢,它可以通过使用 IData 查找数据,然后在添加到列表时转换为 T。我们只需要确保所有数据类都有一个没有参数的构造函数。似乎我们无法在接口或基类中定义构造函数。但无论如何,总比对每个类都重复相同的代码要好。
猜你喜欢
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多