.NET에서 불변의 배열이 가능합니까?
-
03-07-2019 - |
문제
어떻게 든 마크 a가 가능합니까? System.Array
불변. 공공 기관/개인 세트 뒤에 놓을 때 재 할당 및 재 할당이 필요하기 때문에 추가 할 수는 없지만 소비자는 여전히 원하는 첨자를 설정할 수 있습니다.
public class Immy
{
public string[] { get; private set; }
}
나는 생각했다 readonly
키워드는 트릭을 수행 할 수 있지만 그런 운은 없습니다.
해결책
ReadOnlyCollection<T>
아마도 당신이 찾고있는 것일 것입니다. 그것은 없습니다 Add()
방법.
다른 팁
그만큼 프레임 워크 설계 지침 배열 사본을 반환하는 것이 좋습니다. 그렇게하면 소비자는 배열에서 항목을 변경할 수 없습니다.
// bad code
// could still do Path.InvalidPathChars[0] = 'A';
public sealed class Path {
public static readonly char[] InvalidPathChars =
{ '\"', '<', '>', '|' };
}
이것들은 더 낫다 :
public static ReadOnlyCollection<char> GetInvalidPathChars(){
return Array.AsReadOnly(InvalidPathChars);
}
public static char[] GetInvalidPathChars(){
return (char[])InvalidPathChars.Clone();
}
그 예는 책에서 바로 있습니다.
참조하십시오 이제 불변의 컬렉션을 사용할 수 있습니다 기본 클래스 라이브러리 (현재 미리보기)에서.
Array.asreadonly 메소드를 사용하여 반환 할 수 있습니다.
모범 사례는 Ilist를 사용하는 것입니다u003CT> 이 정확한 이유 때문에 공개 API의 배열보다는 대신. 준비 적 멤버 변수가 생성자 외부에서 설정되는 것을 방지하지만 발견 한대로 사람들이 배열에 요소를 할당하는 것을 방해하지는 않습니다.
보다 어레이는 다소 유해하다고 생각합니다 자세한 내용은.
편집하다: 배열 만 읽을 수는 없지만 @shahkalpesh가 지적한대로 array.asreadonly ()를 통해 읽기 전용 ILIST 구현으로 변환 할 수 있습니다.
.NET은 가장 단순하고 전통적인 사용 사례를 제외한 모든 배열에서 멀어지는 경향이 있습니다. 다른 모든 것에 대해, 다양한 열거 가능한/수집 구현이 있습니다.
일련의 데이터를 불변으로 표시하려면 기존 배열에서 제공하는 기능을 넘어서고 있습니다. .NET은 동등한 기능을 제공하지만 기술적으로 배열 형태는 아닙니다. 어레이에서 불변의 컬렉션을 얻으려면 사용하십시오. Array.AsReadOnly<T>
:
var mutable = new[]
{
'a', 'A',
'b', 'B',
'c', 'C',
};
var immutable = Array.AsReadOnly(mutable);
immutable
a ReadOnlyCollection<char>
사례. 보다 일반적인 사용 사례로서 ReadOnlyCollection<T>
모든 일반에서 IList<T>
구현.
var immutable = new ReadOnlyCollection<char>(new List<char>(mutable));
일반적인 구현이어야합니다. 평범한 늙음 IList
작동하지 않으면 기존 배열 에서이 방법을 사용할 수 없다는 의미입니다. IList
. 이것은 사용 가능성을 밝히게합니다 Array.AsReadOnly<T>
일반적으로 기존 배열을 통해 접근 할 수없는 일반 구현에 대한 액세스를 얻는 빠른 수단으로.
ReadOnlyCollection<T>
불변의 배열에서 기대할 모든 기능에 액세스 할 수 있습니다.
// Note that .NET favors Count over Length; all but traditional arrays use Count:
for (var i = 0; i < immutable.Count; i++)
{
// this[] { get } is present, as ReadOnlyCollection<T> implements IList<T>:
var element = immutable[i]; // Works
// this[] { set } has to be present, as it is required by IList<T>, but it
// will throw a NotSupportedException:
immutable[i] = element; // Exception!
}
// ReadOnlyCollection<T> implements IEnumerable<T>, of course:
foreach (var character in immutable)
{
}
// LINQ works fine; idem
var lowercase =
from c in immutable
where c >= 'a' && c <= 'z'
select c;
// You can always evaluate IEnumerable<T> implementations to arrays with LINQ:
var mutableCopy = immutable.ToArray();
// mutableCopy is: new[] { 'a', 'A', 'b', 'B', 'c', 'C' }
var lowercaseArray = lowercase.ToArray();
// lowercaseArray is: new[] { 'a', 'b', 'c' }
추가해야 할 유일한 것은 배열입니다 암시합니다 돌연변이. 함수에서 배열을 반환 할 때 고객 프로그래머에게 물건을 변경할 수 있고 변경해야한다고 제안합니다.
Matt의 답변에 따르면, Ilist는 배열에 대한 완전한 추상 인터페이스이므로 추가, 제거 등을 허용합니다. Lippert가 불변성이 필요한 ienumerable의 대안으로 제안하는 이유는 확실하지 않습니다. (편집하다: ILIST 구현은 이러한 종류의 것을 좋아한다면 이러한 돌연변이 방법에 대해 예외를 제외 할 수 있기 때문입니다).
아마도 목록에있는 항목에도 변이 된 상태가있을 수 있다는 점을 명심해야 할 또 다른 사항이있을 수 있습니다. 발신자가 해당 상태를 수정하는 것을 실제로 원하지 않으면 몇 가지 옵션이 있습니다.
목록의 항목이 불변인지 확인하십시오 (예에서와 같이 문자열은 불변).
모든 것의 깊은 클론을 반환하십시오. 따라서 어쨌든 배열을 사용할 수 있습니다.
항목에 대한 Reshonly 액세스를 제공하는 인터페이스를 반환합니다.
interface IImmutable
{
public string ValuableCustomerData { get; }
}
class Mutable, IImmutable
{
public string ValuableCustomerData { get; set; }
}
public class Immy
{
private List<Mutable> _mutableList = new List<Mutable>();
public IEnumerable<IImmutable> ImmutableItems
{
get { return _mutableList.Cast<IMutable>(); }
}
}
iimmutable 인터페이스에서 액세스 할 수있는 모든 값은 그 자체가 불변 (예 : 문자열)이어야합니다.
당신이 희망 할 수있는 최선은 자신의 컬렉션을 확장하기 위해 기존 컬렉션을 확장하는 것입니다. 가장 큰 문제는 모든 통화가 새 컬렉션을 반환해야하기 때문에 기존 컬렉션 유형과 다르게 작동해야한다는 것입니다.
체크 아웃하고 싶을 수도 있습니다 내 대답 객체에 컬렉션 노출에 대한 더 많은 아이디어에 대한 비슷한 질문에.