메소드를 정적으로 만들 수는 있지만 그렇게해야합니까?


366

Resharper는 asp.net 페이지 당 여러 기능을 정적으로 작성할 수있는 기능을 선호합니다. 내가 정적으로 만들면 도움이됩니까? 그것들을 정적으로 만들고 유틸리티 클래스로 옮겨야합니까?


20
Resharper가 실제로 "낮은 응집력, 낮은 응집력"을 외치지 않습니까? 메소드가 실제로 해당 클래스에 속하는지 살펴볼 시간입니다.
PK

답변:


245

정적 메서드와 인스턴스 메서드
10.2.5 C # 언어 사양의 정적 멤버와 인스턴스 멤버 는 차이점을 설명합니다. 일반적으로 정적 메소드는 인스턴스 메소드에 비해 성능이 약간 향상되지만 다소 극단적 인 상황에서만 가능합니다 (자세한 내용은 이 답변 참조 ).

FxCop 또는 코드 분석 상태의 규칙 CA1822 :

"[멤버를 정적으로 표시] 후에 컴파일러는 각 멤버에 대해 가상이 아닌 호출 사이트를 생성하여 각 호출에 대해 런타임시 현재 오브젝트 포인터가 널이 아닌지 확인하지 못하게합니다. 이로 인해 성능이 크게 향상 될 수 있습니다. 경우에 따라 현재 개체 인스턴스에 액세스하지 못하면 정확성 문제가 발생합니다. "

유틸리티 클래스
디자인에 의미가없는 한 유틸리티 클래스로 이동해서는 안됩니다. 정적 메서드가 ToRadians(double degrees)각도를 나타내는 클래스 와 관련된 메서드 와 같이 특정 형식과 관련된 경우 해당 메서드가 해당 형식의 정적 멤버로 존재하는 것이 좋습니다 (이는 데모 목적으로 복잡한 예입니다).


2
> 컴파일러는이 멤버들에게 비가 상 호출 사이트를 내 보냅니다. 실제로는 "컴파일러가 방출 할 수 있습니다 ..."입니다. 잠재적 버그를 해결하기 위해 call 대신 callvirt를 사용하는 C # 컴파일러에 대해 기억합니다.
Jonathan Allen

24
FxCop 1.36에서 직접 잘라 붙여 넣습니다. FxCop이 틀렸다면 충분히 공정합니다.
Jeff Yates

5
@Maxim 확실하지 않은 "헛소리"문장; 낯선 사람에게 접근하는 아주 무례한 방법입니다. 그러나 기본 사항은 유효합니다. 나는 물건을 조금 업데이트했습니다 (9 년 전 이었으므로 원래 주장의 기초를 기억하지 못합니다).
Jeff Yates

10
@Maxim 포인트가 유효하지 않습니다. 9 년 전에는 평가가 좋지 않았다고 확신합니다. 나는 실수 (또는 실수를 수정하는 편집)를 지적하지만 다른 사람들에 대해 무례하거나 기대하지 않는 의견에 감사한다. "헛소리"라고 부르지 마십시오. 그것은 선의의 실수 나 무지에 대해 정직하기보다는 속이려는 의도를 암시합니다. 무례하다. 나는 여기에 도움을주기 위해 자원 봉사를하고 무례하게 대할 때 무의미하다고 느낀다. 무엇을 불쾌하게할지 말하지 마라 – 그것은 당신의 선택이 아니라 나의 선택이다. 존중하고 성실하게 요점을 밝히는 방법을 배우십시오. 감사합니다.
Jeff Yates

2
@Maxim 델리게이트가 각 인스턴스와 함께 저장되지 않지만 상태 비 저장 클래스의 각 인스턴스는 실제로 힙에서 일부 메모리를 차지하므로 불필요한 오버 헤드가 발생합니다. 일반적으로 서비스를 인스턴스화하는 것은 응용 프로그램의 주요 경로는 아니지만 응용 프로그램에서 이러한 객체를 많이 만들면 정적 메서드를 사용하여 피할 수있는 GC 압력이 발생합니다. OP의 원래 주장은 극한 상황에서 정적 메소드가 상태 비 저장 인스턴스에 비해 성능 이점을 제공한다는 점에서 적절하게 미묘한 차이가 있으며 유효하다는 것입니다.
Asad Saeeduddin

259

성능, 네임 스페이스 오염 등은 모두 제 생각에 부차적입니다. 논리적 인 것이 무엇인지 스스로에게 물어보십시오. 메소드가 유형의 인스턴스에서 논리적으로 작동합니까 아니면 유형 자체와 관련이 있습니까? 후자 인 경우 정적 메서드로 만듭니다. 제어되지 않는 유형과 관련된 경우에만 유틸리티 클래스로 이동하십시오.

인스턴스에 논리적으로 작동하지만 인스턴스 상태를 아직 사용하지 않는 메소드가있는 경우가 있습니다 . 예를 들어, 파일 시스템을 구축 할 때 디렉토리 개념이 있지만 아직 구현하지 않은 경우 파일 시스템 객체의 종류를 반환하는 속성을 작성할 수 있으며 항상 "file"-인스턴스와 논리적으로 관련되어 있으므로 인스턴스 메소드 여야합니다. 메소드를 가상으로 만들려는 경우에도 중요합니다. 특정 구현에는 상태가 필요하지 않지만 파생 클래스는 필요할 수 있습니다. 예를 들어, 컬렉션이 읽기 전용인지 여부를 묻습니다. 해당 컬렉션의 읽기 전용 형식을 아직 구현하지 않았을 수도 있지만 유형이 아닌 컬렉션 자체의 속성입니다.


1
기본 클래스 메소드가 실제로 아무것도하지 않는 것이 일반적이기 때문에 좋은 린터가 메시지를 비가 상 메소드로 제한하는 옵션이 있어야한다고 생각합니다. 재정의 메소드는 일반적으로 무언가를 수행하지만 항상 그런 것은 아닙니다. 메소드가 본질적으로 인스턴스를 무시하지만 인스턴스가 올바른 메소드를 선택해야하는 빈 iEnumerable과 같은 클래스를 사용하는 것이 유용한 경우가 있습니다.
supercat

2
"인스턴스에서 논리적으로 작동하지만 인스턴스 상태를 아직 사용하지 않는 메소드가있는 경우가 있습니다. 예를 들어"이 인스턴스에서 "예를 들어"를 사용하는 것을 즐겼습니다.
PaulBinder 21 년

56

static클래스 내 에서 메소드를 표시하면 인스턴스 멤버를 사용하지 않는 것이 분명하므로 코드를 통해 스키밍 할 때 알아두면 도움이됩니다.

개념적으로 밀접하게 연결된 다른 클래스와 공유하지 않는 한 반드시 다른 클래스로 옮길 필요는 없습니다.


22

나는 이것이 당신의 경우에는 일어나지 않을 것이라고 확신하지만, 일부 코드에서 본 하나의 "나쁜 냄새"는 많은 정적 메소드를 사용하여 고통을 겪어야했습니다.

불행하게도, 이들은 특정 애플리케이션 상태를 가정 한 정적 메소드였습니다. (확실히, 우리는 응용 프로그램 당 한 명의 사용자 만 가질 것입니다! User 클래스가 정적 변수에서 그것을 추적하지 않는 이유는 무엇입니까?) 전역 변수에 액세스하는 영광스러운 방법이었습니다. 또한 정적 생성자 (!)가 있었으며 거의 ​​항상 나쁜 생각입니다. (나는 합리적인 예외가 몇 가지 있다는 것을 안다).

그러나 정적 메서드는 실제로 개체 인스턴스의 상태에 의존하지 않는 도메인 논리를 제외 할 때 매우 유용합니다. 코드를 훨씬 더 읽기 쉽게 만들 수 있습니다.

올바른 장소에 배치하십시오. 정적 메소드가 다른 오브젝트의 내부 상태를 방해하지 않고 조작합니까? 그들의 행동이 그 클래스들 중 하나에 속하는 것이 좋은 사례가 될 수 있습니까? 우려 사항을 올바르게 분리하지 않으면 나중에 두통에 걸릴 수 있습니다.


4
문제는 정적 메소드가 아닌 정적 필드 / 속성에 관한 것입니다.
Asad Saeeduddin

10

이것은 흥미로운 내용입니다.

http://thecuttingledge.com/?p=57

ReSharper는 실제로 메소드를 정적으로 만들 것을 제안하지 않습니다. 예를 들어 서명에 나타나는 클래스 중 하나와 반대로 해당 메소드가 해당 클래스에있는 이유를 스스로에게 묻어 야합니다.

그러나 여기 resharper documentaion의 내용이 있습니다 : http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
나는이 시점이 과소 평가되었다고 생각한다. 이 도구가 실제로 말하는 것은이 메서드가 다른 클래스 멤버에서만 작동한다는 것입니다. 그것이 어떤 종류의 명령 (또는 "사용 사례"또는 "인터랙 터") 객체라면, 다른 객체를 조작하는 것은 책임이 있습니다. 그러나 Feature Envy 와 비슷하게 들리는 다른 하나의 클래스 만 조작하는 경우 .
Greg Greg

9

@Jason True의 답변 에 추가하기 위해 메소드에 '정적'을 적용한다고해서 메소드가 '순수'하다는 것을 보장하지는 않습니다. 선언 된 클래스와 관련하여 상태가 없지만 상태가있는 다른 '정적'객체 (응용 프로그램 구성 등)에 잘 액세스 할 수 있습니다. 이것은 항상 나쁜 것은 아니지만 그 이유 중 하나입니다. 나는 개인적으로 정적 메소드를 선호하는 경향이 있습니다. 순결한 메소드는 순수하면 주변 상태에 대해 걱정할 필요없이 테스트하고 격리 할 수 ​​있다는 것입니다.


6

주어진 시나리오에서 가장 읽기 쉽고 직관적 인 작업을 수행해야합니다.

실제로 일어나고있는 유일한 것은 하나의 추가 매개 변수 ( this)가 인스턴스 메소드의 스택으로 푸시되는 것이므로 가장 극단적 인 상황을 제외하고는 성능 인수가 좋지 않습니다 .


6

클래스 내의 복잡한 논리의 경우 인스턴스 입력이 메소드 서명에 명확하게 정의되어 인스턴스 부작용이 발생하지 않는 격리 된 논리를 만드는 데 유용한 전용 정적 메소드를 발견했습니다. 모든 출력은 반환 값 또는 출력 / 참조 매개 변수를 통해 이루어져야합니다. 복잡한 논리를 부작용없이 코드 블록으로 분류 하면 코드의 가독성과 개발 팀의 신뢰도가 향상됩니다.

반면에, 그것은 유틸리티 방법의 확산에 의해 오염 된 클래스로 이어질 수 있습니다. 평소처럼 논리적으로 명명, 문서화 및 팀 코딩 규칙을 일관되게 적용하면이를 완화 할 수 있습니다.


5

ReSharper는 논리를 확인하지 않습니다. 메소드가 인스턴스 멤버를 사용하는지 여부 만 확인합니다. 메소드가 개인용이고 인스턴스 메소드에 의해서만 호출되는 경우 이는 인스턴스 메소드를 표시하는 표시입니다.


3

함수가 여러 페이지에서 공유되는 경우이를 기본 페이지 클래스에 넣은 다음 해당 기능을 사용하는 모든 asp.net 페이지에서 상속 할 수 있습니다 (그리고 함수는 여전히 정적 일 수 있음).


3

메서드를 정적으로 만들면 먼저 해당 클래스의 인스턴스를 만들지 않고도 클래스 외부에서 메서드를 호출 할 수 있습니다. 이는 타사 공급 업체 개체 또는 애드온으로 작업 할 때 유용합니다. con.Writeline ()을 호출하기 전에 먼저 콘솔 객체 "con"을 만들어야한다고 상상해보십시오.


Java는 con.Writeline ()을 호출하기 전에 콘솔 객체를 생성하는 팩토리 인스턴스를 생성해야합니다.
ScottMichaud

2

네임 스페이스 오염을 제어하는 ​​데 도움이됩니다.


8
메서드를 정적으로 만드는 것은 네임 스페이스 오염을 방지하는 데 어떻게 도움이됩니까?
lockstock

1
경험을 통해 정적 메서드를 사용하여 메서드를 클래스로 그룹화하면 다른 라이브러리 나 내장 함수와 충돌 할 수있는 느슨한 함수의 "잡아 넣는"모든 접두사를 접두어들이는 경험을 피할 수 있습니다. 정적 메소드를 사용하면 클래스 이름 아래에 효과적으로 네임 스페이스가 지정됩니다. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi

0

그냥 내 tuppence : 모든 공유 정적 메소드를 유틸리티 클래스에 추가하면 추가 할 수 있습니다

using static className; 

코드를 더 빨리 입력하고 읽기 쉽게 만드는 using 문에. 예를 들어, 상속받은 일부 코드에서 "전역 변수"라고하는 것을 많이 가지고 있습니다. 인스턴스 클래스 인 클래스에서 전역 변수를 만들지 않고 전역 변수를 전역 클래스의 정적 속성으로 설정했습니다. 지저분한 경우에는 작업을 수행하며 정적 네임 스페이스가 이미 참조되어 있기 때문에 이름으로 속성을 참조 할 수 있습니다.

이것이 좋은 습관인지 아닌지 전혀 모른다. C # 4/5에 대한 많은 정보와 리팩토링을위한 레거시 코드가 너무 많아서 Roselyn 팁이 나를 안내하도록 노력하고 있습니다.

조이


0

정적 메소드와 인스턴스 메소드의 차이점을 이미 이해했으면합니다. 또한 긴 답변과 짧은 답변이있을 수 있습니다. 긴 답변은 이미 다른 사람에 의해 제공되었습니다.

내 짧은 대답 : 예, Resharper가 제안하면 정적 메소드로 변환 할 수 있습니다. 그렇게해도 아무런 해가 없습니다. 오히려 메소드를 정적으로 만들면 실제로 메소드를 보호하여 불필요하게 인스턴스 멤버를 해당 메소드에 삽입하지 않습니다. 이런 식으로 OOP 원칙 " 클래스 및 멤버의 액세스 가능성 최소화 "를 달성 할 수 있습니다 .

ReSharper가 인스턴스 메소드를 정적 메소드로 변환 할 수 있다고 제안 할 때 실제로 "왜이 메소드가 상태를 사용하지 않기 때문에이 클래스에 앉아 있는가?" 그래서 그것은 당신에게 생각의 음식을 제공합니다. 그런 다음 해당 메소드를 정적 유틸리티 클래스로 이동해야 할 필요성을 인식 할 수 있습니다. SOLID 원칙에 따라 수업에는 하나의 핵심 책임 만 있어야합니다. 따라서 클래스를 더 잘 정리할 수 있습니다. 때로는 인스턴스 클래스에서도 도우미 메서드가 필요합니다. 이 경우 #region 도우미 내에 유지할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.