IList<IList <T >> to IReadonlyCollection<IReadonlyCollection <T >>
У меня есть список массива строк, и я хотел бы сделать обе коллекции только для чтения.
Итак, у меня есть этот код:
public XmlPatternTree(IList<string> nodeNames, IList<IList<string>> attributeNames,
IList<IList<string>> attributeValues) : this()
{
NodeNames = new ReadOnlyCollection<string>(nodeNames);
AttributeNames = new ReadOnlyCollection<ReadOnlyCollection<string>>();
AttributeValues = attributeValues;
Depth = NodeNames.Count;
}
Моя проблема заключается в том, что присвоения AttributeNames и AttributeValues вызывают ошибку компиляции, кажется, что я могу создать коллекцию ReadonlyCollection ReadonlyCollection из не доступной только для чтения коллекции объектов, не доступных только для чтения.
Есть ли что-то, что я могу сделать, кроме перебора всех значений и добавления их в список?
Спасибо
3 ответа
Если вы измените свой тип с IList<string>
чтобы просто List<string>
тогда это должно работать:
attributeNames.Select((x) => x.AsReadOnly()).ToList().AsReadOnly();
Если вы не можете изменить сигнатуру вашего метода (т.е. вы должны сохранить IList<string>
), то вы можете сделать это:
attributeNames.Select((x) => x.ToList().AsReadOnly()).ToList().AsReadOnly();
Если версия.net framework больше 4.0, то общая версия List<>
реализует IReadOnlyCollection<>
интерфейс. Если вам удобнее, вы можете изменить свою подпись с IList<ILIst<>>
в List<List<>>
и должно работать нормально.
AttributeNames = attributeNames;
AttributeValues = attributeValues;
Просто записка о ковариации IReadOnlyList<out T>
тип (аналогично ответу Васила Орешенского).
Если вы решили иметь:
public XmlPatternTree(IReadOnlyList<string> nodeNames,
IReadOnlyList<IReadOnlyList<string>> attributeNames,
IReadOnlyList<IReadOnlyList<string>> attributeValues) : this()
{
NodeNames = nodeNames;
AttributeNames = attributeNames;
AttributeValues = attributeValues;
}
public IReadOnlyList<string> NodeNames { get; private set; }
public IReadOnlyList<IReadOnlyList<string>> AttributeNames { get; private set; }
public IReadOnlyList<IReadOnlyList<string>> AttributeValues { get; private set; }
public int Depth => NodeNames.Count;
в вашем классе упомянутая ковариация означает, что вы можете использовать ссылочные преобразования, а не какие-либо преобразования внутри другого класса, как в:
var nn = new List<string>();
var an = new List<string[]>();
var av = new List<string[]>();
// populate 'nn', 'an', and 'av'
// the following compiles with no wrapper class:
var tree = new XmlPatternTree(nn, an, av);
Конечно, люди могут привести интерфейсы обратно к реальным типам, таким как List<string[]>
и изменять коллекции без использования отражения, если они предполагают, что тип действительно является этим списком массивов. Тем не менее, это было бы довольно злокачественно, так что вы можете предположить, что это не проблема, если только "хорошие" люди используют ваш класс
PS! То, что я сказал и кодировал выше с IReadOnlyList<out T>
можно было бы также сделать с IReadOnlyCollection<out T>
поскольку оно ковариантно (out
"). Вы бы просто не имели доступа к индексаторам свойств (таких как var name = tree.AttrbuteNames[idx1][idx2]
). Но тогда вы могли бы использовать HashSet<>
и аналогичные, которые не являются IReadOnlyList<>
,