C #에서 필드를 '읽기 전용'으로 표시하면 어떤 이점이 있습니까?


295

멤버 변수를 읽기 전용으로 선언하면 어떤 이점이 있습니까? 수업 기간 동안 누군가가 가치를 변경하는 것을 막거나이 키워드를 사용하면 속도 나 효율성이 향상됩니까?


8
좋은 외부 답변 : dotnetperls.com/readonly
OneWorld

3
흥미 롭군 이것은 본질적 으로이 Java 질문 stackoverflow.com/questions/137868/ 의 C #에 해당합니다 ... 여기 토론은 훨씬 덜 가열되지만 ... 흠 ...
RAY

7
그것은 협조 할 수있다 readonly구조 유형의 필드가의 구성원의 호출하기 때문에, 단순히 돌연변이되지 않은 변경 가능한 필드에 비해 성능 저하를 부과 readonly분야의 복사본을 만들기 위해 컴파일러의 원인이됩니다 값 타입의 필드와 호출을 그것에 회원.
supercat

답변:


171

readonly키워드는 런타임에서 산출되는 값을 멤버 변수 상수를 선언하는 데 사용하지만, 허용된다. 이것은 const수정 자 (modifier)로 선언 된 상수와 다르며 , 컴파일시 값을 설정해야합니다. 를 사용 readonly하면 선언 또는 필드가 속한 개체의 생성자에서 필드 값을 설정할 수 있습니다.

상수를 참조하는 외부 DLL을 다시 컴파일하지 않으려는 경우에도 사용하십시오 (컴파일 시간에 대체되기 때문에).


193

읽기 전용 필드를 사용하면 성능이 향상되지 않는다고 생각합니다. 객체가 완전히 구성되면 해당 필드가 새로운 값을 가리킬 수 없는지 확인하는 것입니다.

그러나 "읽기 전용"은 런타임에 CLR에 의해 시행되므로 다른 유형의 읽기 전용 의미론과는 매우 다릅니다. readonly 키워드는 CLR에서 확인할 수있는 .initonly로 컴파일됩니다.

이 키워드의 실제 장점은 변경 불가능한 데이터 구조를 생성하는 것입니다. 정의에 의한 불변 데이터 구조는 일단 생성 된 후에는 변경할 수 없습니다. 이를 통해 런타임시 구조의 동작을 쉽게 추론 할 수 있습니다. 예를 들어, 불변의 구조를 다른 임의의 코드 부분으로 전달할 위험이 없습니다. 그들은 그것을 바꿀 수 없으므로 그 구조에 대해 안정적으로 프로그래밍 할 수 있습니다.

다음은 불변성의 이점 중 하나에 대한 좋은 항목입니다. 스레딩


6
이것을 읽으면 stackoverflow.com/questions/9860595/… 읽기 전용 멤버는 수정 될 수 있으며 .net에 의해 일관성이없는 행동처럼 보입니다
Akash Kava

69

를 사용 readonly하면 성능상의 이점이 없으며 적어도 어느 곳에서도 언급 한 적이 없습니다. 일단 초기화되면 수정을 방지하기 위해 제안한대로 정확하게 수행하기위한 것입니다.

따라서보다 강력하고 읽기 쉬운 코드를 작성하는 데 도움이됩니다. 이와 같은 것의 실질적인 이점은 팀에서 일하거나 유지 보수를 할 때 발생합니다. readonly코드에서 해당 변수의 사용에 대한 계약을 맺는 것과 비슷한 것을 선언 합니다. 같은 다른 키워드와 같은 방법으로 문서를 추가로 생각 internal하거나 private, 당신은 "이 변수가 초기화 후 수정할 수 없습니다"라고하고 있으며, 또한 당신에게있는 거 수행 및을 을.

따라서 클래스를 만들고 readonly의도적으로 일부 멤버 변수 를 표시 하면 나중에 자신이나 다른 팀 멤버가 클래스를 확장하거나 수정할 때 실수를 저지르는 것을 방지 할 수 있습니다. 내 의견으로는, 그것은 가치가있는 이점입니다 (댓글에서 doofledorfer가 언급 한 것처럼 추가 언어 복잡성으로 적은 비용으로).


그리고 otoh는 언어를 예표합니다. 그러나 귀하의 이익 진술을 거부하지 않습니다.
dkretz 2016

3
동의하지만, 한 사람 이상이 코드 작업을 할 때 실질적인 이점이 있다고 생각합니다. 코드 내에 작은 설계 설명을 사용하는 것과 같습니다. 사용법에 대한 계약입니다. 아마 대답에 넣어야 할 것입니다.
Xiaofu

7
이 답변과 토론은 실제로 제 생각에 가장 좋은 답입니다 +1
Jeff Martin

@ 샤오 푸 : 당신은이 세상의 어느 누구도 이해하기 어려운 어리석은 마음을 설명 할 수 없다는 readonly hahaha 아름다운 설명이라는 생각을 일정하게 만들었습니다.
Learner

즉, 코드 에서이 값은 언제든지 변경되어서는 안된다는 의도를 유지하고 있습니다.
Andez

51

매우 실용적인 용어로 말하면 :

dll A의 const를 사용하고 dll B가 그 const를 참조하면 해당 const의 값은 dll B로 컴파일됩니다. dll A를 해당 const의 새 값으로 재배치하면 dll B는 여전히 원래 값을 사용합니다.

읽기 전용 인 dll A 및 dll B 참조에서 읽기 전용을 사용하는 경우 해당 읽기 전용은 항상 런타임에 조회됩니다. 이는 dll A를 해당 읽기 전용의 새 값으로 재배치하면 dll B가 해당 새 값을 사용한다는 의미입니다.


4
차이점을 이해하기에 좋은 실용적인 예입니다. 감사.
Shyju

반면에 const성능이 향상 될 수 있습니다 readonly. 다음은 코드에 대한 좀 더 자세한 설명입니다. dotnetperls.com/readonly
Dio Phung

2
나는 가장 큰 실용적인 용어가 런타임에 계산 된 값을 readonly필드 에 저장하는 능력이라는이 대답에서 빠졌다고 생각 합니다. a new object();를 저장할 const수 없으며 ID를 변경하지 않고 컴파일 타임에 다른 어셈블리에 대한 참조와 같은 값이 아닌 것을 구울 수 없으므로 의미가 있습니다.
binki

14

컴파일러가 읽기 전용 키워드의 존재 여부에 따라 성능을 최적화 할 수있는 경우가 있습니다.

읽기 전용 필드도 static으로 표시된 경우에만 적용됩니다 . 이 경우 JIT 컴파일러는이 정적 필드가 절대 변경되지 않는다고 가정 할 수 있습니다. JIT 컴파일러는 클래스의 메소드를 컴파일 할 때이를 고려할 수 있습니다.

일반적인 예 : 클래스 에는 생성자에서 초기화 되는 정적 읽기 전용 IsDebugLoggingEnabled 필드가 있을 수 있습니다 (예 : 구성 파일 기반). 실제 메소드가 JIT 컴파일되면 디버그 로깅이 사용 가능하지 않은 경우 컴파일러가 코드의 전체 부분을 생략 할 수 있습니다.

이 최적화가 실제로 현재 버전의 JIT 컴파일러에서 구현되는지 확인하지 않았으므로 이것은 단지 추측입니다.


이것에 대한 소스가 있습니까?
Sedat Kapanoglu

4
현재 JIT 컴파일러는 실제로 이것을 구현하며 CLR 3.5부터 사용합니다. github.com/dotnet/coreclr/issues/1079
mirhagk

읽기 전용 필드가 읽기 전용이 아니라 읽기 쓰기이기 때문에 읽기 전용 필드에서 최적화를 수행 할 수 없습니다. 그것들은 대부분의 컴파일러가 존중하고 읽기 전용 필드의 값을 리플렉션을 통해 쉽게 덮어 쓸 수 있다는 컴파일러 힌트 일뿐입니다 (부분적으로 신뢰할 수있는 코드는 아니지만).
Christoph

9

읽기 전용은 값 자체에만 적용되므로 참조 유형을 사용하는 경우 읽기 전용은 참조가 변경되지 않도록 보호합니다. 인스턴스의 상태는 읽기 전용으로 보호되지 않습니다.


4

params를 readonly사용하여 생성자 외부 에서 필드를 설정 하는 해결 방법이 있다는 것을 잊지 마십시오 out.

조금 지저분하지만 :

private readonly int _someNumber;
private readonly string _someText;

public MyClass(int someNumber) : this(data, null)
{ }

public MyClass(int someNumber, string someText)
{
    Initialise(out _someNumber, someNumber, out _someText, someText);
}

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
    //some logic
}

여기에 대한 추가 토론 : http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx


4
필드는 여전히 생성자에 할당되어 있습니다. 값이 단일 표현식, 분해 복합 유형 또는 참조 시맨틱에 의한 호출을 통해 할당 된 값인지 여부는 중요하지 않습니다 out.
user2864740

이것은 질문에 대답조차하지 않습니다.
Sheridan

2

놀랍게도 Jon Skeet이 Noda Time 라이브러리를 테스트 할 때 발견 한 것처럼 읽기 전용은 실제로 코드 속도가 느려질 수 있습니다. 이 경우 20 초 동안 실행 된 테스트는 읽기 전용을 제거한 후 4 초 밖에 걸리지 않았습니다.

https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/


3
필드가 readonly structC # 7.2 의 유형 인 경우 필드를 비 읽기 전용으로 설정하면 얻을 수있는 이점이 사라집니다.
Jon Skeet 2016 년

1

사전 정의 또는 사전 계산 된 값이 프로그램 전체에서 동일하게 유지되어야하는 경우 상수를 사용해야하지만 런타임에 제공해야하는 값이 있지만 한 번 할당 된 값은 프로그램 전체에서 동일하게 유지되어야합니다. 읽기 전용. 예를 들어 프로그램 시작 시간을 할당해야하거나 사용자가 제공 한 값을 객체 초기화시 저장해야하며 추가 변경을 제한해야하는 경우 읽기 전용을 사용해야합니다.


1

이 질문에 대답하기 위해 기본 측면 추가 :

set연산자 를 생략하면 속성을 읽기 전용으로 표현할 수 있습니다 . 따라서 대부분의 경우 readonly키워드를 속성 에 추가 할 필요가 없습니다 .

public int Foo { get; }  // a readonly property

이와 대조적으로 : readonly유사한 효과를 얻으려면 필드에 키워드가 필요합니다 .

public readonly int Foo; // a readonly field

따라서 어떤 이유로 든 원하는 경우 필드를 속성으로 변경할 필요 readonly없이 set연산자없이 속성과 유사한 쓰기 방지 수준을 달성 할 수있는 것처럼 필드를 표시하는 한 가지 이점 이 있습니다.


2 사이에 행동에 차이가 있습니까?
petrosmm

0

전용 읽기 전용 배열에주의하십시오. 이것들이 클라이언트로 객체로 노출되면 (내가했던 것처럼 COM interop에 대해이 작업을 수행 할 수 있음) 클라이언트는 배열 값을 조작 할 수 있습니다. 배열을 객체로 반환 할 때는 Clone () 메서드를 사용하십시오.


20
아니; ReadOnlyCollection<T>배열 대신에 노출하십시오 .
SLaks

이 질문에 대한 답변을 제공하지 않기 때문에 이것은 대답이 아닌 설명이어야합니다 ...
Peter

재미있게도, 나는 지난 주에 다른 게시물에서 그것을했을 때 논평이 아니라 이런 종류의 것을 대답으로 생각한다고 들었습니다.
Kyle Baran

2013 년 ImmutableArray<T>부터 인터페이스를 사용 IReadOnlyList<T>하거나 ( ReadOnlyCollection) 클래스를 래핑 하지 않도록 ( ) 사용할 수 있습니다 . 기본 어레이와 비슷한 성능을 제공합니다. blogs.msdn.microsoft.com/dotnet/2013/06/24/…
Charles Taylor

0

값 비싼 DependencyProperties가 필요 없으므로 WPF의 성능 이점이 있습니다. 이것은 컬렉션에 특히 유용 할 수 있습니다


0

읽기 전용 마킹 사용의 또 다른 흥미로운 부분은 싱글 톤에서 필드가 초기화되지 않도록 보호하는 것입니다.

예를 들어 csharpindepth의 코드에서 :

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

readonly는 Singleton 필드가 두 번 초기화되지 않도록 보호하는 작은 역할을합니다. 또 다른 세부 사항은 언급 된 시나리오의 경우 const가 컴파일 시간 동안 작성을 강제하기 때문에 const를 사용할 수는 없지만 싱글 톤은 런타임에 작성한다는 것입니다.


0

readonly선언시 초기화되거나 생성자에서만 값을 얻을 수 있습니다. 달리 const초기화하고 동시에 선언해야합니다. readonly 모든 것이 const 있고 생성자 초기화

코드 https://repl.it/HvRU/1

using System;

class MainClass {
    public static void Main (string[] args) {

        Console.WriteLine(new Test().c);
        Console.WriteLine(new Test("Constructor").c);
        Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
        // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
        // variable initializer)
    }


    public class Test {
        public readonly string c = "Hello World";
        public Test() {

        }

        public Test(string val) {
          c = val;
        }

        public string ChangeC() {
            c = "Method";
            return c ;
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.