const 배열 선언


458

다음과 비슷한 것을 쓸 수 있습니까?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

static, public static string [] 제목 = new string [] { "German", "Spanish"};
Ray

답변:


691

예, 그러나 readonly대신 다음과 const같이 선언해야합니다 .

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

그 이유는 const컴파일 타임에 값이 알려진 필드에만 적용 할 수 있기 때문입니다 . 표시 한 배열 이니셜 라이저는 C #에서 상수 표현식이 아니므로 컴파일러 오류가 발생합니다.

readonly이 값을 선언하면 런타임까지 값이 초기화되지 않기 때문에이 문제가 해결됩니다 (배열을 처음 사용하기 전에 초기화 된 것이 보장되지만).

궁극적으로 달성하고자하는 것이 무엇인지에 따라 열거 형 선언을 고려할 수도 있습니다.

public enum Titles { German, Spanish, Corrects, Wrongs };

115
점을 유의 배열 여기 물론, 읽기 전용 아니다; 제목 [2] = "Welsh"; 런타임에 잘 작동 것
마크 Gravell

46
당신은 아마 정적 인 것을 원할 것입니다
tymtam

4
클래스 본문이 아닌 메소드 본문에서 "const"배열을 선언하는 것은 어떻습니까?
serhio

19
다운 투표에 대해 유감이지만 const도 정적을 의미합니다. 어레이를 읽기 전용으로 선언하는 것은 해결 방법에 가깝지 않습니다. 그것은 할 필요가 readonly static요청 된 의미의 유사성을 가지고.
Anton

3
@Anton, 당신과 당신의 "추종자"가 downvote를 제거 했습니까? 나에게 static그것이 작동하게 할 필요는 없지만 Titles인스턴스를 가지지 않고 참조 할 가능성을 추가 하지만 다른 인스턴스의 값을 변경할 가능성을 제거하십시오 (예 : 해당 readonly필드의 값을 변경하는 것에 따라 매개 변수가있는 생성자를 가질 수 있음 ).
Sinatr

57

배열을 다음과 같이 선언 할 수 있습니다 readonly 있지만 readonlyarray 요소를 변경할 수 있습니다 .

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Cody가 제안한대로 열거 형 또는 IList를 사용하십시오.

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();

31
.NET 4.5 이상에서는 목록을 IList <string> 대신 IReadOnlyList <string>로 선언 할 수 있습니다.
Grzegorz Smulko

분명히하기 위해 여전히 IReadOnlyList의 값을 변경할 수 있습니다 (요소를 추가하거나 제거하지 마십시오). 그러나 예, IReadOnlyList로 선언하는 것이 IList보다 낫습니다.
KevinVictor

문제는 const아닙니다 readonly...
Yousha Aleayoub

51

배열은 객체이고 런타임에만 만들 수 있고 const 엔터티는 컴파일 타임에 확인되므로 'const'배열을 만들 수 없습니다.

대신 배열을 "읽기 전용"으로 선언하면됩니다. 런타임에 값을 설정할 수 있다는 점을 제외하면 const와 동일한 효과가 있습니다. 한 번만 설정할 수 있으며 이후 읽기 전용 (즉, const) 값입니다.


2
이 글은 배열을 상수로 선언 할 수없는 이유를 강조합니다
Radderz

1
상수 배열을 선언 할 수 있습니다. 문제는 상수 값으로 초기화하는 것입니다. 유념해야 할 유일한 작업 예 const int[] a = null;는별로 유용하지는 않지만 실제로 배열 상수의 인스턴스입니다.
waldrumpus

이것이 유일한 정답입니다.
Yousha Aleayoub

17

C # 6부터 다음과 같이 작성할 수 있습니다.

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

참조 : C # .NET을 : 새로운 및 향상된 C를 # 6.0 (특히 장 "표현 바디 기능 및 속성")

이렇게하면 읽기 전용 정적 속성이 만들어 지지만 반환 된 배열의 내용을 변경할 수는 있지만 속성을 다시 호출하면 변경되지 않은 원래 배열이 다시 나타납니다.

명확히하기 위해이 코드는 다음과 동일합니다 (또는 실제로는 속기).

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

이 방법에는 단점이 있습니다. 새로운 배열은 각각의 참조마다 실제로 인스턴스화되므로 매우 큰 배열을 사용하는 경우 가장 효율적인 솔루션이 아닐 수 있습니다. 그러나 동일한 배열을 재사용하면 (예를 들어 개인 속성에 배치하여) 배열의 내용을 변경할 가능성이 다시 열립니다.

불변 배열 (또는 목록)을 원한다면 다음을 사용할 수도 있습니다.

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

그러나 여전히 문자열 []로 다시 캐스팅하고 내용을 변경할 수 있으므로 변경의 위험이 있습니다.

((string[]) Titles)[1] = "French";

1
이 경우 필드 대신 속성을 사용하면 어떤 이점이 있습니까?
nicolay.anykienko

2
필드는 각 호출에서 새 객체를 반환 할 수 없습니다. 속성은 기본적으로 일종의 "변장 기능"입니다.
mjepson

1
마지막 옵션을 언급했다면 필드 또는 속성을 모두 사용하여 수행 할 수 있지만 공개이기 때문에 속성을 선호합니다. 속성을 도입 한 이후로 공개 필드를 사용하지 않습니다.
mjepson

1
첫 번째 접근 방식의 또 다른 단점이 있습니다. Titles[0]예를 들어 할당 시도가 자동으로 무시되는 경우 컴파일 오류가 발생하지 않습니다 . 매번 배열을 다시 생성하는 비효율 성과 결합 하여이 접근법이 가치가 있는지 궁금합니다. 대조적으로, 두 번째 접근 방식은 효율적이므로 불변성을 없애기 위해 길을 떠나야합니다.
mklement0

6

IReadOnlyList 인터페이스 뒤에 배열을 선언하면 런타임에 선언 된 상수 값을 가진 상수 배열을 얻습니다.

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

.NET 4.5 이상에서 사용 가능합니다.


6

.NET 프레임 워크 V4.5의 + 솔루션 에 향상 tdbeckett의 대답 :

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

참고 : 컬렉션이 개념적으로 일정 static하면 클래스 수준 에서 컬렉션 을 선언하는 것이 좋습니다.

위 :

  • 배열을 사용 하여 속성의 암시 적 백업 필드를 한 번 초기화합니다 .

    • 하는 것으로 { get; }- 즉, 단지 속성 선언 게터을 - 암시 적으로 읽기 전용 속성 자체를 만드는 것입니다 (결합하는 시도 readonly와 함께하는 것은 { get; }실제로 구문 오류입니다).

    • 또는 질문에서와 같이 속성 대신 필드 를 생성하기 위해 { get; }및 추가 readonly를 생략 할 수 있지만 공개 데이터 멤버를 필드가 아닌 속성으로 노출 하는 것이 좋은 습관입니다.

  • 다음 과 관련하여 진정으로 강력하게 읽기 전용 (개념적으로 일정하고 일단 생성 된) 인 배열 과 유사한 구조 ( 인덱스 액세스 허용 )를 만듭니다 .

    • 컬렉션 의 전체 수정 방지 (예 : 요소를 제거 또는 추가하거나 변수에 새 컬렉션을 할당)
    • 개별 요소의 수정 방지 .
      (심지어 간접적으로 변형 불가능 -와는 달리 IReadOnlyList<T>용액 캐스트 요소에 대한 쓰기 액세스를 얻기 위해 사용될 수있다 같이 mjepsen의 도움 않음 . 동일한 취약점이 적용 인터페이스 이름 유사성에도 불구하고, 이는 로 클래스 , 심지어 지원하지 않는 인덱스 액세스를 액세스 어레이 형상 제공하는 것이 근본적으로 적합하지 않다.)(string[])
      IReadOnlyCollection<T> ReadOnlyCollection

1
@mortb : 불행히도 IReadOnlyCollection인덱스 액세스를 지원하지 않으므로 여기서 사용할 수 없습니다. 또한 IReadOnlyList(인덱스 액세스 권한이있는) 처럼로 다시 캐스팅하여 요소를 조작하기 쉽습니다 string[]. 즉, ReadOnlyCollection(문자열 배열을 캐스트 할 수없는) 가장 강력한 솔루션입니다. 게터를 사용하지 않는 것이 옵션이지만 ( 공개 데이터 를 참고하여 답변을 업데이트했습니다) 공개 데이터를 사용하면 속성을 유지하는 것이 좋습니다.
mklement0

5

내 필요 static에 따라 불가능 대신 배열을 정의 const하고 작동합니다. public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };


1
constOP 예제에서 간단히 제거해 도 작동하지만 Titles인스턴스 또는 모든 값 을 변경할 수 있습니다 . 이 답변의 요점은 무엇입니까?
Sinatr

@ Sinatr, 나는 C #에서 일할 때 3 년 전에 대답했습니다. 나는 그것을 떠났고 이제는 Java 세계에 있습니다. 아마 추가하는 것을 잊었을 수도 있습니다readonly
ALZ

두 번째 생각하면, 당신의 대답은 직접입니다 OP 코드 작업을하는 방법을 어떤없이, const/의 readonly단순히 고려 가 작동하고 (같은 경우 const구문 실수였다). 어떤 사람들에게는 귀중한 답변 인 것 같습니다 (아마도 const실수 로 사용하려고 했습니까?).
Sinatr

5

다른 접근법을 취할 수 있습니다 : 배열을 나타내는 상수 문자열을 정의한 다음 필요할 때 문자열을 배열로 분할하십시오.

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

이 접근 방식은 상수를 제공하여 구성에 저장하고 필요할 때 배열로 변환 할 수 있습니다.


8
분할을 수행하는 데 드는 비용이 const를 정의하여 얻은 모든 이점을 훨씬 능가한다고 생각합니다. 그러나 상자 밖에서 독창적 인 접근 방식과 사고를하려면 +1하십시오! ;)
Radderz

나는 똑같은 해결책을 게시하려고했는데 가혹하고 부정적인 말과는 달리 이것을 보았습니다. 실제로 const를 Attribute에 전달 한 다음 속성 생성자의 값을 내가 필요한 것을 얻습니다. 각 인스턴스마다 속성이 생성되지 않기 때문에 성능 비용이 발생하는 이유가 없습니다.
Kalpesh Popat

4

완벽을 기하기 위해 이제 우리는 또한 ImmutableArrays를 사용할 수 있습니다. 이것은 정말로 불변이어야합니다 :

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

System.Collections.Immutable NuGet 참조 필요

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx


3

이것은 원하는 것을 수행하는 방법입니다.

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

읽기 전용 배열을 수행하는 것과 매우 유사합니다.


8
당신은 그냥 그렇게 할 수 있습니다 public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; 어쨌든 ReadOnlyCollection으로 만들면 모든 검색에서 목록을 다시 만들 필요가 없습니다.
Nyerguds

3

이것이 유일한 정답입니다. 현재는이 작업을 수행 할 수 없습니다.

다른 모든 답변은와 비슷 하지만 상수와 동일하지 않은 정적 읽기 전용 변수를 사용하도록 제안 합니다. 상수는 어셈블리에 하드 코딩됩니다. 정적 읽기 전용 변수는 객체가 초기화 될 때 한 번만 설정할 수 있습니다.

이들은 때때로 상호 교환이 가능하지만 항상 그런 것은 아닙니다.


2

나는 당신이 그것을 읽기 전용으로 만들 수 있다고 생각합니다.


2

배열은 아마도 런타임에서만 평가할 수있는 것들 중 하나 일 것입니다. 컴파일 타임에 상수를 평가해야합니다. "const"대신 "readonly"를 사용해보십시오.


0

대안으로, 읽기 전용 배열에서 수정할 수있는 요소를 해결하기 위해 정적 속성을 대신 사용할 수 있습니다. 개별 요소는 계속 변경할 수 있지만 이러한 변경 사항은 어레이의 로컬 사본에서만 수행됩니다.

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

물론 매번 새로운 문자열 배열이 만들어 지므로 이는 특히 효율적이지 않습니다.


0

최선의 대안 :

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.