내가 사용하고 비주얼 스튜디오 2010 + ReSharper에서를 하고 다음과 같은 코드에 경고를 표시합니다 :
if (rect.Contains(point))
{
...
}
rect
은 readonly Rectangle
필드이고 Resharper는 다음 경고를 표시합니다.
"값 유형의 읽기 전용 필드에 대해 임 퓨어 메소드가 호출되었습니다."
불순한 방법은 무엇이며이 경고가 표시되는 이유는 무엇입니까?
내가 사용하고 비주얼 스튜디오 2010 + ReSharper에서를 하고 다음과 같은 코드에 경고를 표시합니다 :
if (rect.Contains(point))
{
...
}
rect
은 readonly Rectangle
필드이고 Resharper는 다음 경고를 표시합니다.
"값 유형의 읽기 전용 필드에 대해 임 퓨어 메소드가 호출되었습니다."
불순한 방법은 무엇이며이 경고가 표시되는 이유는 무엇입니까?
답변:
먼저 Jon, Michael 및 Jared의 답변은 본질적으로 정확하지만 추가하고 싶은 몇 가지가 더 있습니다.
"불순한"방법이란 무엇을 의미합니까?
순수한 방법을 특성화하는 것이 더 쉽습니다. "순수한"방법에는 다음과 같은 특성이 있습니다.
예를 들어, Math.Cos
순수한 방법입니다. 출력은 입력에만 의존하며 입력은 호출에 의해 변경되지 않습니다.
불순한 방법은 순수하지 않은 방법입니다.
읽기 전용 구조체를 불순한 메서드로 전달하는 위험은 무엇입니까?
떠오르는 두 가지가 있습니다. 첫 번째는 Jon, Michael 및 Jared가 지적한 것이며 Resharper가 경고하는 것입니다. 구조체에서 메서드를 호출 할 때 메서드가 변수를 변경하려는 경우 항상 수신자 인 변수에 대한 참조를 전달합니다.
그렇다면 변수가 아닌 값에 대해 이러한 메서드를 호출하면 어떻게 될까요? 이 경우 임시 변수를 만들고 값을 복사 한 다음 변수에 대한 참조를 전달합니다.
읽기 전용 변수는 생성자 외부에서 변경할 수 없기 때문에 값으로 간주됩니다. 따라서 우리는 변수를 다른 변수에 복사하고 있으며, 불순한 방법은 변수를 변경하려는 경우 복사본을 변경하는 것입니다.
이것이 readonly 구조체를 수신자 로 전달할 위험입니다 . 읽기 전용 필드를 포함하는 구조체를 전달할 위험도 있습니다. 읽기 전용 필드를 포함하는 구조체는 일반적인 관행이지만 기본적으로 유형 시스템에 현금화 할 자금이 없다는 수표를 작성합니다. 특정 변수의 "읽기 전용"은 저장소 소유자가 결정합니다. 참조 유형의 인스턴스는 자체 저장소를 "소유"하지만 값 유형의 인스턴스는 그렇지 않습니다!
struct S
{
private readonly int x;
public S(int x) { this.x = x; }
public void Badness(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
// This should be the same, right?
Console.WriteLine(this.x);
}
}
this.x
x는 읽기 전용 필드이고 Badness
생성자가 아니기 때문에 변경되지 않을 것이라고 생각합니다 . 그러나...
S s = new S(1);
s.Badness(ref s);
... 그것의 허위성을 분명히 보여줍니다. this
과 s
같은 변수를 참조하고, 그 변수는 읽기 전용되지 않습니다!
struct Id {
private readonly int _id;
public Id(int id) { _id = id; }
public int ToInt() => _id;
}
가 왜 불순한가요?
return
. 이를 바탕으로 유일한 기준은 메서드에 [Pure]
속성 이 있는지 여부 입니다.
rect
. 의 복사본이 메서드에 rect
전달된다는 Contains
말입니까?
불순한 방법은 그 가치를 그대로 남겨 두는 것이 보장되지 않는 방법입니다.
.NET 4에서는 메서드와 형식을 데코레이션 [Pure]
하여 순수로 선언 할 수 있으며 R #은이를 인식합니다. 불행히도 다른 사람의 구성원에게 적용 할 수 없으며 내가 아는 한 .NET 3.5 프로젝트에서 유형 / 구성원이 순수하다고 R #을 설득 할 수 없습니다. (이것은 노다 타임에서 항상 나를 물고 있습니다.)
아이디어는 당신이 변수에있는 변이를 메서드를 호출하고 있지만 읽기 전용 필드를 호출하는 경우, 아마 것입니다 하지 R 번호는 이것에 대해 경고합니다, 그래서 당신이 원하는 일을. 예를 들면 :
public struct Nasty
{
public int value;
public void SetValue()
{
value = 10;
}
}
class Test
{
static readonly Nasty first;
static Nasty second;
static void Main()
{
first.SetValue();
second.SetValue();
Console.WriteLine(first.value); // 0
Console.WriteLine(second.value); // 10
}
}
실제로 순수한 모든 메서드가 그렇게 선언 된 경우 정말 유용한 경고가 될 것입니다. 불행히도 그들은 그렇지 않으므로 많은 오 탐지가 있습니다 :(
JetBrains.Annotations.PureAttribute
대신 사용할 수 있으며 System.Diagnostics.Contracts.PureAttribute
ReSharper 코드 분석에 대해 동일한 의미를 가지며 .NET 3.5, .NET 4 또는 Silverlight에서 동일하게 작동해야합니다. XML 파일을 사용하여 소유하지 않은 어셈블리에 외부 주석을 달 수도 있습니다 (ReSharper bin 경로의 ExternalAnnotations 디렉토리를 확인하십시오). 정말 유용 할 수 있습니다!
System.Diagnostics.Contracts.PureAttribute
R # 8.2에서이 경고를 억제하지 않는 것을 발견했습니다 JetBrains.Annotations.PureAttribute
. 두 속성은 또한 다른 설명을 가지고 있습니다. contracts Pure
속성은 "결과는 매개 변수에만 의존 함"을 의미하는 반면, JetBrains Pure
는 결과를 계산하는 데 사용되는 객체 상태를 제외하지 않고 "표시 상태 변경을 일으키지 않음"을 의미합니다. (하지만 여전히 계약 Pure
이 경고에 같은 효과를 가지고 있지 아마 버그입니다.)
짧은 대답은 이것이 잘못된 긍정이며 경고를 무시해도 안전하다는 것입니다.
더 긴 대답은 읽기 전용 값 형식에 액세스하면 복사본 이 만들어 지므로 메서드에 의한 값 변경은 복사본에만 영향을줍니다. ReSharper Contains
는 이것이 순수한 방법 이라는 것을 인식하지 못합니다 (부작용이 없음을 의미 함). Eric Lippert가 여기에 대해 설명합니다. Readonly Structs 변형
private readonly SpinLock _spinLock = new SpinLock();
과 같습니다 .-이러한 잠금은 완전히 쓸모가 없습니다 (읽기 전용 수정자는 Enter 메서드가 호출 될 때마다 즉석 복사가 생성되기 때문에)
Reshaprer가 메서드 Contains
가 rect
값을 변경할 수 있다고 믿는 것처럼 들립니다 . 때문에 rect
, A는 readonly struct
C # 컴파일러 값 사본은 운전자로부터 돌연변이 방법을 방지 할 수 readonly
필드. 기본적으로 최종 코드는 다음과 같습니다.
Rectangle temp = rect;
if (temp.Contains(point)) {
...
}
Resharper는 일시적으로 발생했기 때문에 즉시 손실되는 방식으로 Contains
돌연변이 가 발생할 수 있음을 경고합니다 rect
.