program story

읽기 전용 필드에 대해 불순한 메소드가 호출 됨

inputbox 2020. 10. 7. 07:38
반응형

읽기 전용 필드에 대해 불순한 메소드가 호출 됨


내가 사용하고 비주얼 스튜디오 2010 + ReSharper에서를 하고 다음과 같은 코드에 경고를 표시합니다 :

if (rect.Contains(point))
{
    ...
}

rectreadonly 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.xx는 읽기 전용 필드이고 Badness생성자가 아니기 때문에 변경되지 않을 것이라고 생각합니다 . 그러나...

S s = new S(1);
s.Badness(ref s);

... 그것의 허위성을 분명히 보여줍니다. thiss같은 변수를 참조하고, 변수는 읽기 전용되지 않습니다!


불순한 방법은 그 가치를 그대로 남겨 두는 것이 보장되지 않는 방법입니다.

.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
    }
}

This would be a really useful warning if every method which was actually pure was declared that way. Unfortunately they're not, so there are a lot of false positives :(


The short answer is that this is a false positive, and you can safely ignore the warning.

The longer answer is that accessing a read-only value type creates a copy of it, so that any changes to the value made by a method would only affect the copy. ReSharper doesn't realize that Contains is a pure method (meaning it has no side effects). Eric Lippert talks about it here: Mutating Readonly Structs


It sounds like Reshaprer believes that the method Contains can mutate the rect value. Because rect is a readonly struct the C# compiler makes defensive copies of the value to prevent the method from mutating a readonly field. Essentially the final code looks like this

Rectangle temp = rect;
if (temp.Contains(point)) {
  ...
}

Resharper is warning you here that Contains may mutate rect in a way that would be immediately lost because it happened on a temporary.


An Impure method is a method that could have side-effects. In this case, Resharper seems to think it could change rect. It probably doesn't but the chain of evidence is broken.

참고URL : https://stackoverflow.com/questions/9927434/impure-method-is-called-for-readonly-field

반응형