Как сделать IEnumerable <T> только для чтения?

Я не уверен, что wrapper в этом случае. Но чтобы ответить на два ваших вопроса: да, можно получить по элементу HTML, и нет, это не рекомендуется.

Вот как вы это сделаете:

// Possible but not advisable
const { container } = render()
// `container` is just a DOM node
const button = container.querySelector('button')

Поскольку вы возвращаете узел DOM, вы можете использовать все обычные API DOM, такие как querySelector .

1112 Теперь, почему это не рекомендуется? Большой интересной особенностью библиотеки реагирования на тестирование является то, что вы тестируете свои компоненты, как это делает пользователь. Это значит не полагаться на детали реализации. Например, у вас нет прямого доступа к состоянию компонента.

Написание тестов таким способом немного сложнее, но позволяет вам писать более надежные тесты.

В вашем случае, я бы сказал, что базовый HTML - это деталь реализации. Что произойдет, если вы измените свою HTML-структуру так, чтобы h1 теперь было h2 или div? Тест сломается. Если вместо этого вы смотрите на эти элементы по тексту, тег становится неактуальным.

В некоторых случаях обычных помощников запросов недостаточно. Для этих событий вы можете использовать data-testid и использовать getByTestId.

12
задан jpaugh 15 June 2017 в 18:23
поделиться

7 ответов

Действительно, IEnumerable<T> уже только для чтения. Это означает, что Вы не можете заменить объекты в базовом наборе с различными объектами. Таким образом, Вы не можете изменить ссылки на Person объекты, которые сохранены в наборе. Тип Person не только для чтения, однако, и так как это - ссылочный тип (т.е. a class), можно изменить его участников через ссылку.

Существует два решения:

  • Используйте a struct как тип возврата (который делает копию значения каждым разом, он возвращается, таким образом, исходное значение не будет изменено — который может быть дорогостоящим, между прочим),
  • Используйте свойства только для чтения на Person введите для выполнения этой задачи.
34
ответ дан 2 December 2019 в 03:25
поделиться

Вы могли сделать deepclone каждого объекта в списке и никогда не возвращать ссылки на Ваши исходные объекты.

public IEnumerable<Person> Get()
{
  return l1
    .Select(p => new Person(){
      FirstName = p.FirstName,
      LastName = p.LastName
    });
}
1
ответ дан 2 December 2019 в 03:25
поделиться

Они не указывают на тот же набор .NET, а скорее, к тому же Person объекты. Строка:

List<Person> p = new List<Person>(list1Instance.Get()); 

копии все элементы Человека от list1Instance.Get() перечислять p. Слово "копии" здесь означает, копирует ссылки. Так, Ваш список и IEnumerable просто, окажись, указать на то же Person объекты.

IEnumerable<T> всегда только для чтения, по определению. Однако объекты внутри могут быть изменяемыми, как в этом случае.

2
ответ дан 2 December 2019 в 03:25
поделиться

IEnumerable<T> только для чтения

p новый набор, который не зависит от list1instance. Ошибка, которую Вы сделали, то, что Вы думали что эта строка list[0].FirstName = "uf1";
только изменил бы один из списков, когда на факте Вы изменяете Person объект.
Эти два набора отличны, у них просто, оказывается, есть те же объекты.
Чтобы доказать, что они отличаются, попытайтесь добавить и удалить объекты из одного из списков, и Вы будете видеть, что другой не затронут.

0
ответ дан 2 December 2019 в 03:25
поделиться

Возвратите новый экземпляр Человека, который является копией p вместо p самостоятельно в Добираются (). Вам будет нужен метод для создания глубокой копии объекта Человека сделать это. Это не сделает их только для чтения, но они будут отличаться, чем те, которые в исходном списке.

public IEnumerable<Person> Get()
{
    foreach (Person p in l1)
    {
        yield return p.Clone();
    }
}
7
ответ дан 2 December 2019 в 03:25
поделиться

В первую очередь, Ваш Список в Вашем классе общедоступен, таким образом, нет ничего останавливающего никого от прямого доступа к самому списку.

Во-вторых, я реализовал бы IEnumerable и возвратил бы это в моем Методе GetEnumerator

return l1.AsReadOnly().GetEnumerator();
0
ответ дан 2 December 2019 в 03:25
поделиться

Если Ваш объект человека является реальным объектом затем, необходимо рассмотреть использование неизменной версии.

 public class Person
 {
     public FirstName {get; private set;}
     public LastName {get; private set;}
     public Person(firstName, lastName)
     {
         FirstName = firstName;
         LastName = lastName;
     }
  }

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

0
ответ дан 2 December 2019 в 03:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: