Подтвердить что ты не робот

Обязательный атрибут свойства общего списка

Можно ли поместить атрибут [Обязательный] в свойство List < > ?

Я связываюсь с общим списком в POST и задавался вопросом, могу ли я сделать ModelState.IsValid(), если свойство имеет в нем 0 элементов?

4b9b3361

Ответ 1

Добавление атрибута Required в свойство стиля списка действительно не делает то, что вы хотите. Будет жаловаться, если список не создан, но не будет жаловаться, если список существует с 0 элементом в нем.

Однако, должно быть достаточно легко получить свой собственный атрибут аннотаций данных и заставить его проверить список для Count > 0. Что-то вроде этого (еще не проверено):

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : ValidationAttribute
{
    private const string defaultError = "'{0}' must have at least one element.";
    public CannotBeEmptyAttribute ( ) : base(defaultError) //
    { 
    }

    public override bool IsValid ( object value )
    {
      IList list = value as IList;
      return ( list != null && list.Count > 0 );
    }

    public override string FormatErrorMessage ( string name )
    {
        return String.Format(this.ErrorMessageString, name);
    }
}

EDIT:

Вам также нужно быть осторожным, как вы привязываете свой список в своем представлении. Например, если вы привязываете List<String> к виду, подобному этому:

<input name="ListName[0]" type="text" />
<input name="ListName[1]" type="text" />
<input name="ListName[2]" type="text" />
<input name="ListName[3]" type="text" />
<input name="ListName[4]" type="text" />

Связывание модели MVC будет всегда помещать 5 элементов в ваш список, все String.Empty. Если это работает в вашем представлении, вашему атрибуту нужно будет немного усложниться, например, используя Reflection, чтобы вытащить параметр типового типа и сравнить каждый элемент списка с default(T) или чем-то.

Лучшей альтернативой является использование jQuery для динамического создания входных элементов.

Ответ 2

Для тех, кто ищет минималистские примеры:

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IEnumerable;
        return list != null && list.GetEnumerator().MoveNext();
    }
}

Это измененный код из принятого ответа. Он подходит в этом случае из вопроса и в еще большем числе случаев, поскольку IEnumerable выше в иерархии System.Collections. Кроме того, он наследует поведение от RequiredAttribute, поэтому нет необходимости в его кодировании явно.

Ответ 3

Модифицированная реализация @moudrick для моего требования

Обязательный атрибут проверки для списка и списка флажков

[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomListRequiredAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IEnumerable;
        return list != null && list.GetEnumerator().MoveNext();
    }
}

Если у вас есть список флажков

[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomCheckBoxListRequiredAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        bool result = false;

        var list = value as IEnumerable<CheckBoxViewModel>;
        if (list != null && list.GetEnumerator().MoveNext())
        {
            foreach (var item in list)
            {
                if (item.Checked)
                {
                    result = true;
                    break;
                }
            }
        }

        return result;
    }
}

Вот моя модель просмотра

public class CheckBoxViewModel
{        
    public string Name { get; set; }
    public bool Checked { get; set; }
}

Использование

[CustomListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<YourClass> YourClassList { get; set; }

[CustomCheckBoxListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<CheckBoxViewModel> CheckBoxRequiredList { get; set; }

Ответ 4

Для тех, кто использует С# 6.0 и кто ищет однострочные:

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
}