【问题标题】:Default value data annotation for empty array空数组的默认值数据注释
【发布时间】:2020-06-04 21:02:10
【问题描述】:

我正在创建一个 .NET Core Web API 并希望调用一个端点来提交客户订单。客户 ID 作为路由参数出现。在请求正文中,可以发送对象数组。每个对象都包含产品 ID 及其数量。但是这个字段是可选的,空订单也可以(以后可以添加产品)。

所以我从这个 DTO 开始

public class CreateCustomerOrderByIdDto
{
    [FromRoute]
    public uint Id { get; set; }

    [FromBody]
    public OrderPosition[] OrderPositions { get; set; }
}

public class OrderPosition
{
    [Range(1, uint.MaxValue)]
    public uint ProductId { get; set; }

    [Range(1, uint.MaxValue)]
    public uint Amount { get; set; }
}

此请求 DTO 应使 OrderPositions 字段可选,但在添加项目时,该项目需要两个属性。我想为OrderPositions 设置一个默认值,如果缺少,所以我认为这个数据注释会做到这一点

[DefaultValue(new OrderPosition[0])]

很遗憾,我收到此错误消息

属性参数必须是常量表达式,'typeof()' 属性参数类型的表达式或数组创建表达式

那么如何将该字段标记为可选并设置默认值?

当不传递订单位置时,数组将被转换为空数组,这样我就可以避免空检查并使用从不运行的循环

【问题讨论】:

  • 你不能用DefaultValueAttribute来做。但是你可以通过在类中引入OrderPosition[] _orderPositions = new OrderPosition[0];字段并将OrderPositions属性重写为get { return _orderPositions; } set { _orderPositions = value ?? new OrderPosition[0]; }
  • 感谢您的回复。我尝试了您的解决方案并对其进行了一些更改hatebin.com/osigtdckfz,但是在传递此主体时两种方式{ "orderPositions": [{}] }我收到此错误An unhandled exception has occurred while executing the request. System.NotSupportedException: Collection was of a fixed size. at System.Array.System.Collections.IList.Add(Object value)
  • 更新评论代码hatebin.com/nbrcqjrdmg
  • 你能用List<OrderPosition>代替数组吗?
  • @Question3r 取决于所使用的解析器,列表起作用而不是数组起作用的原因是,如果集合已经存在,则解析器只会向其中添加解析项。对于数组,长度是固定的,因此不能更改。

标签: c# .net


【解决方案1】:

数组的问题在于它的长度是固定的。您可以使用Array.Resize() 调整数组的大小,但这也需要固定长度。

更好的方法是使用 List 而不是数组:

public class CreateCustomerOrderByIdDto
{
    [FromRoute]
    public uint Id { get; set; }

    [FromBody]
    public List<OrderPosition> OrderPositions { get; set; }
}

默认情况下,列表对象OrderPositions 将具有null 值;这是表示列表中不存在任何项目的好方法。

如果你仍然需要列表默认为空,而不是null,你可以设置默认值如下:

public List<OrderPosition> OrderPositions { get; set; } = new List<OrderPosition>();

【讨论】:

    【解决方案2】:

    也许您可以使用List&lt;OrderPosition&gt; 代替数组。然后在构造函数中将其初始化为空列表

    public class CreateCustomerOrderByIdDto
    {
        public CreateCustomerOrderByIdDto()
        {
            this.OrderPositions = new List<OrderPosition>();
        }
        [FromRoute]
        public uint Id { get; set; }
    
        [FromBody]
        public List<OrderPosition> OrderPositions { get; set; }
    }
    
    public class OrderPosition
    {
        [Range(1, uint.MaxValue)]
        public uint ProductId { get; set; }
    
        [Range(1, uint.MaxValue)]
        public uint Amount { get; set; }
    }
    

    【讨论】:

      【解决方案3】:

      与 hphp 的回答类似,您可以像使用任何 c# 类一样设置默认值:

      public class CreateCustomerOrderByIdDto
      {
          [FromRoute]
          public uint Id { get; set; }
      
          [FromBody]
          public OrderPosition[] OrderPositions { get; set; } = new OrderPosition[0]; // auto-initialize it here. 
      
          // alternatively you can use a constructor, but I prefer setting the property like above
          public CreateCustomerOrderByIdDto
          {
              OrderPositions = new OrderPosition[0];
          }
      }
      
      public class OrderPosition
      {
          [Range(1, uint.MaxValue)]
          public uint ProductId { get; set; }
      
          [Range(1, uint.MaxValue)]
          public uint Amount { get; set; }
      }
      

      如果您不喜欢这些想法并且您正在使用 Newtonsoft.Json,您还可以利用序列化事件,并对它们执行默认值设置器:https://www.newtonsoft.com/json/help/html/SerializationCallbacks.htm

      【讨论】:

      • 感谢您的回复。问题是我得到了这个错误然后Collection was of a fixed size。如果我不希望它可以为空,我想我不能为此使用数组
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-19
      • 2014-09-01
      • 1970-01-01
      • 2014-07-12
      • 2018-05-26
      • 2020-09-01
      相关资源
      最近更新 更多