Страница бритвы веб-приложения C # - Как преодолеть исключение IndexOutOfRange при редактировании коллекции? - PullRequest
0 голосов
/ 16 мая 2019

Я начинаю работу со страницами Razor, и у меня возникает следующая проблема:

У меня есть эта модель

public class Order
{
    public int OrderId { get; set; }
    public string Customer { get; set; }
    public List<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
    public int OrderItemId { get; set; }
    public string Item { get; set; }
    public decimal Price { get; set; }
}

Я привязываю это так на Edit.cshtml.cs

public class EditModel : PageModel
{
    [BindProperty]
    public Order Order { get; set; }
    public void OnPost()
    {
    }
}

А в моем Edit.cshtml я так использую

@for (byte i = 0; i <= 5; i++)
{
    <input asp-for="Order.OrderItems[i].OrderItemId" />
    <input asp-for="Order.OrderItems[i].Item" />
    <input asp-for="Order.OrderItems[i].Price">
}

Мой цикл всегда должен быть от 0 до 5, но в коллекции OrderItems может быть даже менее 6 элементов.

Теперь, это прекрасно работает на странице New.cshtml, где Order является новым объектом, а OrderItems пустым. Но когда я пытаюсь редактировать существующую запись, я получаю сообщение об ошибке:

ArgumentOutOfRangeException: Index was out of range.
Must be non-negative and less than the size of the collection.

Есть ли способ преодолеть эту ошибку без необходимости вручную заполнять коллекцию OrderItems, чтобы соответствовать длине цикла?

Ответы [ 2 ]

2 голосов
/ 16 мая 2019

Прежде всего, я считаю, что вы не должны использовать цикл For с, скажем, 5 итерациями, не зная наверняка, что вам придется повторять 5 раз.Возможно, вы могли бы использовать ForEach с гарантированным циклом или что-то еще в вашем представлении.

Тем не менее, даже если это не чистый способ, вы можете просто добавить окружающий оператор if вокруг ваших входных данных.Что-то вроде:

@for (byte i = 0; i <= 5; i++)
{
    @if(Order.OrderItems[i] != null)
    {
        <input asp-for="Order.OrderItems[i].OrderItemId" />
        <input asp-for="Order.OrderItems[i].Item" />
        <input asp-for="Order.OrderItems[i].Price">
    }
}

Но опять же, использование ForEach петли было бы гораздо лучшим выбором.

РЕДАКТИРОВАТЬ

На основе вашегокомментарий, вот что вы можете сделать:

@if(Order.OrderItems[i] != null)
{
    <input asp-for="Order.OrderItems[i].OrderItemId" />
    <input asp-for="Order.OrderItems[i].Item" />
    <input asp-for="Order.OrderItems[i].Price">
}
else
{
    // new form to post the 3 inputs, allowing to reload the page with the new non null values ...
}
0 голосов
/ 16 мая 2019

Судя по комментариям, вы указываете, что ваша модель должна иметь (как минимум) 6 элементов в своем списке.Если это так, то эта логика принадлежит модели.Возможно, что-то вроде этого:

public class Order
{
    public int OrderId { get; set; }
    public string Customer { get; set; }

    private List<OrderItem> _orderItems;
    public List<OrderItem> OrderItems
    {
        get { return _orderItems; }
        set
        {
            _orderItems = value;
            if (_orderItems == null)
                _orderItems = new List<OrderItem>();
            while (_orderItems.Count < 6)
                _orderItems.Add(new OrderItem());
        }
    }

    public Order()
    {
        // invoke the setter logic on object creation
        this.OrderItems = null;
    }
}

Есть, конечно, множество способов организовать логику, это только один пример.Но дело в том, что если модель должна иметь хотя бы 6 элементов в своем списке, то модель - это то место, где вы бы это гарантировали.(В качестве альтернативы, если вы чувствуете, что в вашем домене должно быть представление , где эта логика гарантирована, и модель может иметь другие длины списка в других местах, которые она использует, тогда, я думаю, вы могли бы включить ту же логику впредставление. Но это кажется маловероятным. Логика, как правило, принадлежит моделям, представления должны просто связываться с этими моделями.)

Есть ли способ преодолеть эту ошибку без необходимости вручную заполнять коллекцию OrderItems длясоответствовать длине цикла?

Нет.Ну, в зависимости от того, как вы определяете «вручную».Вам нужно написать код где-нибудь для выполнения вашей пользовательской логики?Да.Вам нужно повторять один и тот же код везде, где вы его используете?Нет, поэтому он относится к модели.

Или, иначе говоря: «Умные структуры данных и тупой код работают намного лучше, чем наоборот».-Эрик Рэймонд

...