List - внутренне хранит массив и отслеживает логический размер списка и размер поддерживающего массива. Добавление элемента является либо простым случаем установки очередного значения в массиве, либо (если массив уже заполнен) копированием существующего содержимого в новый массив большего размера (обычно в два раза, т.е. происходит удвоение, но это недокументированно) и затем установки в нем значения. Сложность O(1) или O(n) в зависимости от того требуется ли копирование значений. Удаление элемента из List требует копирования расположенных за ним элементов на позицию назад, поэтому сложность составляет O(n-k), где k - индекс удаляемого элемента. По индексу RemoveAt() удалять значительно быстрее чем по значению Remove(), т.к. во втором случае происходит сравнение каждого элемента где бы он не находился сложность O(n).
**Массивы** - самый низкий уровень коллекций в .Net. Унаследованы от System.Array, и они единственные имеют прямую поддержку в среде CLR. Массивы всегда изменяемы в терминах своих элементов, но всегда фиксированы в терминах своих размеров.
Foreach для массива использует его свойство Length и индексатор массива, а не создает объект итератора.
**LinkedList** - связанный список, каждый элемент которого имеет ссылку на предыдущий и следующий элемент. Быстро можно удалять, вставлять новые элементы, т.к. происходит только изменение ссылок на соседних узлах. Проход по коллекции тоже эффективен, но разумеется нет индекса.
**Dictionary** - подобно List хранит свои элементы в массиве, со всеми вытекающими по вставке и увеличению размера последствиями. Для реализации эффективного поиска использует хештаблицу. Можно либо применять стандартные функции хеширования и эквивалентности внутри самих объектов ключей, либо передать реализацию IEqualityComparer в аргументе конструктора. Ключи должны быть уникальными, но хешкоды могут совпадать, что снижает эффективность поиска. Словарь даст отказ, если ключи являются изменяемыми и меняют свои хешкоды после того, как были вставлены в словарь. Внутри этого словаря нет гарантии порядка следования элементов, так что рассчитывать на него нельзя. Вставка происходит на основе ключа (что-то вроде индекса), а не последовательности заполнения словаря.
**ReadOnlyDictionary<,>** - просто оболочка, которая скрывает все изменяемые операции за явной реализацией интерфейса, и генерирует исключение если они все же вызываются. Но если лежащая в основе коллекция (та что передается конструктору) модифицируется, то модификации будут видны через оболочку.
[ContractClass(typeof(IArrayContract))]
public interface IArray
{ контракт }
[ContractClassFor(typeof(IArray))]
internal abstract class IArrayContract : IArray
{ проверка входных и выходных параметров контрактов }Глава 7. Метаданные и валидация модели
Аннотации данных для отображения свойств
Основы валидации
Атрибуты валидации
Валидация модели в контроллере
Отображение ошибок валидации
Создание собственной логики валидацииpublic class MovieViewModel : IValidatableObject
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Genre { get; set; }
public int GenreId { get; set; }
public string Director { get; set; }
public string Writer { get; set; }
public string Producer { get; set; }
public DateTime ReleaseDate { get; set; }
public byte Rating { get; set; }
public string TrailerURI { get; set; }
public bool IsAvailable { get; set; }
public int NumberOfStocks { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var validator = new MovieViewModelValidator();
var result = validator.Validate(this);
return result.Errors.Select(item => new ValidationResult(item.ErrorMessage, new[] { item.PropertyName }));
}
}
public class MovieViewModelValidator : AbstractValidator<MovieViewModel>
{
public MovieViewModelValidator()
{
RuleFor(movie => movie.GenreId).GreaterThan(0)
.WithMessage("Select a Genre");
RuleFor(movie => movie.Director).NotEmpty().Length(1,100)
.WithMessage("Select a Director");
RuleFor(movie => movie.Writer).NotEmpty().Length(1,50)
.WithMessage("Select a writer");
RuleFor(movie => movie.Producer).NotEmpty().Length(1, 50)
.WithMessage("Select a producer");
RuleFor(movie => movie.Description).NotEmpty()
.WithMessage("Select a description");
RuleFor(movie => movie.Rating).InclusiveBetween((byte)0, (byte)5)
.WithMessage("Rating must be less than or equal to 5");
RuleFor(movie => movie.TrailerURI).NotEmpty().Must(ValidTrailerURI)
.WithMessage("Only Youtube Trailers are supported");
}
private bool ValidTrailerURI(string trailerURI)
{
return (!string.IsNullOrEmpty(trailerURI) && trailerURI.ToLower().StartsWith("https://www.youtube.com/watch?"));
}
}
Практическое руководство Настройка анализа кода для проекта управляемого кода. Только не включайте все правила сразу, предупреждений будут сотни, включайте по одному, как исправите недочеты (внимательно читая предупреждения на сайте Microsoft), применяйте другие, и так до включения "All".