【问题标题】:Can a class property be both T or IEnumerable<T>?类属性可以同时是 T 还是 IEnumerable<T>?
【发布时间】:2020-04-07 18:45:11
【问题描述】:

类中的属性是否可以同时接受 TIEnumerable&lt;T&gt; 作为其值?

我正在尝试为 API 成功响应实现 DTO,其中属性 Data 既可以是单个 JSON 对象,也可以是 JSON 对象的集合。有没有办法使用一个类来实现这一点,还是我需要两个类,一个用于T,另一个用于IEnumerable&lt;T&gt;

这是我的代码:

public class ApiClass<T> where T : class, IEnumerable<T>
{
    public ApiClass(IEnumerable<T> data)
    {
        Data = data;
        Message = "Enumerable data received";
    }

    public ApiClass(T data)
    {
        Data = data;
        Message = "Object data received";
    }

    private IEnumerable<T> Data { get; set; }

    private string Message{ get; set; }
}

这就是我打算在序列化对象实例之后得到的结果:

{
  "data": {
    "Id": 1,
    "Name": "John"
  },
  "message": "Object data received."
}

{
  "data": [
    {
      "Id": 1,
      "Name": "John"
    },
    {
      "Id": 2,
      "Name": "Mary"
    }
  ],
  "message": "Object data received."
}

此代码可以编译,但是当我尝试在return new ApiClass&lt;User&gt;(new User()); 中创建新对象时收到以下错误消息:

Error: CS0311 - The type 'XPTO.User' cannot be used as type parameter 'T' in the generic type or method 'ApiClass&lt;T&gt;'. There is no implicit reference conversion from 'XPTO.User' to 'System.Collections.Generic.IEnumerable&lt;XPTO.User&gt;'.

【问题讨论】:

  • 将第 11 行更改为:Data = new T[] { data };
  • 作为不得不使用这样的 API 的人,我会说“请不要”。是否有特定原因不总是为该属性使用集合?
  • @Max 这将导致一个包含 1 个项目的 Json 数组,因为在这种情况下 OP 希望数据成为单个对象而不是数组。
  • 错误信息对我来说似乎很清楚:你的XPTO.User 类型没有实现IEnumerable&lt;XPTO.User&gt;。所以很自然,您不能将该类型用作ApiClass&lt;T&gt; 的类型参数。在 C# 中,类型 T 实现 IEnumerable&lt;T&gt; 肯定是合法的(很少见,但合法)。但是,如果这是您要施加的约束,则类型必须满足该约束。请注意,在任何情况下,属性仍将被序列化为集合,而不是单个实例,因为这是属性的类型
  • @Max 对代码进行了一些调整,并且成功了。但是我想我应该创建单独的类,以避免客户端总是像 ryanman 指出的那样在单个项目上选择第一个,并且因为我根本没有理由使用单个类,正如 tieson-t 所指出的那样。

标签: c# asp.net-mvc asp.net-core asp.net-web-api


【解决方案1】:

使用多个类,让程序员根据他们需要的返回来决定从哪个类继承。例如:

public class ApiClass
{
    public string Message{ get; private set; }
}

public class ApiClass<T> : ApiClass where T : class
{
    public ApiClass(T data)
    {
        Data = data;
        Message = "Object data received";
    }

    public T Data { get; private set; }
}

public class ArrayApiClass<T> : ApiClass where T : class
{
    public ArrayApiClass(IEnumerable<T> data)
    {
        Data = data;
        Message = "Enumerable data received";
    }

    public IEnumerable<T> Data { get; private set; }
}

【讨论】:

    【解决方案2】:

    我不相信有办法做到这一点。作为可能使用 API 的人,您不希望人们猜测他们的数据是否为数组!

    相反,如果没有集合,则拥有一个名为“MainData”的属性或其他东西。否则人们宁愿只获取数组中的第一个元素,如果有约定总是有一个集合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-24
      • 2020-04-20
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多