【发布时间】:2020-04-07 18:45:11
【问题描述】:
类中的属性是否可以同时接受 T 或 IEnumerable<T> 作为其值?
我正在尝试为 API 成功响应实现 DTO,其中属性 Data 既可以是单个 JSON 对象,也可以是 JSON 对象的集合。有没有办法使用一个类来实现这一点,还是我需要两个类,一个用于T,另一个用于IEnumerable<T>?
这是我的代码:
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<User>(new User()); 中创建新对象时收到以下错误消息:
Error: CS0311 - The type 'XPTO.User' cannot be used as type parameter 'T' in the generic type or method 'ApiClass<T>'. There is no implicit reference conversion from 'XPTO.User' to 'System.Collections.Generic.IEnumerable<XPTO.User>'.
【问题讨论】:
-
将第 11 行更改为:Data = new T[] { data };
-
作为不得不使用这样的 API 的人,我会说“请不要”。是否有特定原因不总是为该属性使用集合?
-
@Max 这将导致一个包含 1 个项目的 Json 数组,因为在这种情况下 OP 希望数据成为单个对象而不是数组。
-
错误信息对我来说似乎很清楚:你的
XPTO.User类型没有实现IEnumerable<XPTO.User>。所以很自然,您不能将该类型用作ApiClass<T>的类型参数。在 C# 中,类型T实现IEnumerable<T>肯定是合法的(很少见,但合法)。但是,如果这是您要施加的约束,则类型必须满足该约束。请注意,在任何情况下,属性仍将被序列化为集合,而不是单个实例,因为这是属性的类型。 -
@Max 对代码进行了一些调整,并且成功了。但是我想我应该创建单独的类,以避免客户端总是像 ryanman 指出的那样在单个项目上选择第一个,并且因为我根本没有理由使用单个类,正如 tieson-t 所指出的那样。
标签: c# asp.net-mvc asp.net-core asp.net-web-api