정적 일 수 있는 C # 메서드는 정적이어야합니까?
우리는 오늘 이것에 대해 논의하고 있었고 나는 일종의 울타리에 있습니다. 몇 줄을 리팩토링하는 긴 방법이 있다고 상상해보십시오. 새 메서드는 부모 메서드에서 몇 개의 지역 변수를 가져와 값을 반환합니다. 이것은 그것을 의미합니다 정적 수 있음을 .
문제는 정적 이어야 합니까? 인스턴스 값을 참조하지 않는다는 점에서 본질적으로 디자인이나 선택에 따라 정적 인 것이 아닙니다.
정적 일 수 있는 C # 메서드는 정적이어야합니까?
우리는 오늘 이것에 대해 논의하고 있었고 나는 일종의 울타리에 있습니다. 몇 줄을 리팩토링하는 긴 방법이 있다고 상상해보십시오. 새 메서드는 부모 메서드에서 몇 개의 지역 변수를 가져와 값을 반환합니다. 이것은 그것을 의미합니다 정적 수 있음을 .
문제는 정적 이어야 합니까? 인스턴스 값을 참조하지 않는다는 점에서 본질적으로 디자인이나 선택에 따라 정적 인 것이 아닙니다.
답변:
때에 따라 다르지. 실제로 두 가지 유형의 정적 메서드가 있습니다.
중소 규모의 코드베이스에서는 두 가지 방법을 서로 바꿔서 사용할 수 있습니다.
첫 번째 범주 (정적 일 수 있음)에있는 메서드가 있고 클래스 상태에 액세스하도록 변경해야하는 경우 정적 메서드를 인스턴스 메서드로 전환 할 수 있는지 확인하는 것이 비교적 간단합니다.
그러나 대규모 코드 기반에서는 많은 수의 호출 사이트가 정적 메서드를 비 정적 메서드로 변환하는 것이 가능한지 너무 비용이 많이 드는지 확인하기 위해 검색을 수행 할 수 있습니다. 여러 번 사람들은 호출 횟수를보고 "좋아 ...이 방법을 변경하지 않는 것이 좋지만 필요한 작업을 수행하는 새 방법을 만드는 것이 좋습니다."라고 말합니다.
결과는 다음 중 하나 일 수 있습니다.
둘 다 나쁘다.
그래서 제 충고는 만약 당신이 200K LOC 이상의 코드 기반을 가지고 있다면, 그것이 반드시 정적이어야 할 경우에만 정적 메서드를 만들 것이라는 것입니다.
비 정적에서 정적으로 리팩토링하는 것은 비교적 쉬우므로 (키워드를 추가하기 만하면 됨), 나중에 (인스턴스 외부의 기능이 필요할 때) 정적이 될 수있는 실제 정적으로 만들려면 할 수 있습니다. 그러나 역 리팩토링, 정적이 될 수있는 인스턴스 메서드로 전환하는 것은 훨씬 더 비쌉니다.
코드 기반이 크면 관념적 순수성보다는 확장의 용이성 측면에서 오류를 일으키는 것이 좋습니다.
따라서 큰 프로젝트의 경우 필요한 경우가 아니면 정적으로 만들지 마십시오. 소규모 프로젝트의 경우 가장 좋아하는 일을하십시오.
나는 것 아니 그것을 만드는 공공 의 정적 멤버 클래스 . 그 이유는 public static으로 만드는 것이 클래스의 유형에 대해 "이 유형은이 동작을 수행하는 방법을 알고있다"뿐만 아니라 "이 동작을 수행하는 것이이 유형의 책임"이라고 말하는 것입니다. 그리고 그 행동은 더 이상 더 큰 유형과 실제 관계가 없습니다.
그렇다고 전혀 정적으로 만들지 않을 것이라는 의미는 아닙니다. 스스로에게 물어보십시오. 새로운 방법이 논리적으로 다른 곳에 속할 수 있습니까? 이에 대해 "예"라고 답할 수 있다면 정적으로 만들고 싶을 것입니다 (또한 이동). 사실이 아니더라도 정적으로 만들 수 있습니다. 표시하지 마십시오 public
.
편의상 적어도 표시 할 수 있습니다 internal
. 이렇게하면 일반적으로 더 적절한 유형에 쉽게 액세스 할 수없는 경우 메서드를 이동할 필요가 없지만 클래스 사용자에게 공개 인터페이스의 일부로 표시되지 않는 방식으로 필요한 곳에 액세스 할 수 있습니다. .
반드시 그런 것은 아닙니다.
공용 메서드를 정적에서 비 정적으로 이동하는 것은 주요 변경 사항이며 모든 호출자 또는 소비자를 변경해야합니다. 메서드가 인스턴스 메서드처럼 보이지만 인스턴스 멤버를 사용하지 않는 경우 미래 보장의 척도로 인스턴스 메서드로 만드는 것이 좋습니다.
예, 그래야합니다. 클래스가 다른 클래스, 메서드 등과 같은 다른 것들에 어떻게 의존 하는지를 측정하는 다양한 결합 메트릭 이 있습니다 . 메서드를 정적으로 만드는 것은 결합 정도를 낮추는 방법입니다. 정적 메서드가 어떤 것도 참조하지 않는다는 것을 확신 할 수 있기 때문입니다. 회원.
나는 그것을 정적으로 표시하면 조금 더 읽기 쉽게 만들 것이라고 생각합니다 ... 그러면 함께 오는 사람은 전체 함수를 읽지 않고도 인스턴스 변수를 참조하지 않는다는 것을 알 것입니다 ...
개인적으로 저는 무국적자의 훌륭한 팬입니다. 메서드가 클래스 상태에 액세스해야합니까? 대답이 '아니오'(아마도 '아니오'이면 정적 메서드로 만드는 것을 고려하지 않을 것입니다), 그래요.
주에 대한 접근은 덜 두통입니다. 다른 클래스에서 필요하지 않은 private 멤버를 숨기는 것이 좋은 생각과 마찬가지로 필요하지 않은 멤버로부터 상태를 숨기는 것이 좋습니다. 액세스 감소는 버그 감소를 의미합니다. 또한 정적 멤버를 스레드로부터 안전하게 유지하는 것이 훨씬 쉽기 때문에 스레딩이 더 쉬워집니다. 런타임에 대한 참조를 전달할 필요가 없기 때문에 성능 고려 사항도있다 이 정적 메서드의 매개 변수로는.
물론 단점은 이전의 정적 메서드가 어떤 이유로 든 상태에 액세스해야한다는 사실을 발견 한 경우이를 변경해야한다는 것입니다. 이제 나는 이것이 공용 API에 문제가 될 수 있음을 이해하므로 이것이 공용 클래스의 공용 메서드 인 경우 이것의 의미에 대해 생각해야 할 것입니다. 그래도 현실 세계에서 이것이 실제로 문제를 일으킨 상황을 본 적이 없지만 어쩌면 운이 좋을 수도 있습니다.
그래, 꼭 가라.
정적 메서드는 비 정적 메서드보다 빠르므로 가능하면 정적이어야하며 비 정적 상태로 두는 특별한 이유가 없습니다 .
실제로 여기에서 캡슐화를 언급하는 사람이 거의 없다는 사실에 놀랐습니다. 인스턴스 메서드는 모든 개인 (인스턴스) 필드, 속성 및 메서드에 자동으로 액세스 할 수 있습니다. 기본 클래스에서 상속 된 모든 보호 된 항목에 추가합니다.
코드를 작성할 때는 가능한 한 적게 노출하고 가능한 한 적게 액세스 할 수 있도록 작성해야합니다.
그렇습니다. 메서드를 정적으로 만드는 경우 발생할 수있는 코드를 빠르게 만드는 것이 중요 할 수 있지만 일반적으로 코드를 가능한 한 버그를 만들 수 없도록 만드는 것이 더 중요합니다. 이를 달성하는 한 가지 방법은 코드가 "비공개 항목"에 가능한 한 적게 액세스하도록하는 것입니다.
OP가이 시나리오에서 잘못 될 수없고 새로운 버그를 생성 할 수있는 리팩토링에 대해 분명히 이야기하고 있기 때문에 이것은 언뜻보기에는 무관 한 것처럼 보일 수 있습니다. 그러나이 리팩토링 된 코드는 향후 유지 관리되고 수정되어 코드가 더 큰 "공격"을 갖게됩니다. 개인 인스턴스 멤버에 대한 액세스 권한이있는 경우 새로운 버그와 관련하여 표면 ". 그래서 일반적으로 여기서 결론은 "네 대부분의 메소드는 정적이어야한다" 는 것입니다. 그리고 이것은 단순히 "캡슐화 및 데이터 숨김의 더 나은 사용 및 '안전한'코드 생성"이기 때문입니다.
개인적으로 나는 그것을 정적으로 만드는 것 외에는 선택의 여지가 없습니다. 이 경우 Resharper는 경고를 발행하고 PM에는 "Resharper의 경고 없음"이라는 규칙이 있습니다.
상황에 따라 다르지만 일반적으로 이러한 메서드를 정적으로 만들지 않습니다. 코드는 항상 변경되며 언젠가는 해당 함수를 가상으로 만들고 하위 클래스에서 재정의하고 싶을 것입니다. 또는 언젠가 인스턴스 변수를 참조해야 할 수도 있습니다. 모든 호출 사이트를 변경해야하는 경우 이러한 변경을 수행하기가 더 어려울 것입니다.
이에 대해 생각하는 가장 좋은 방법은 다음과 같습니다. 클래스의 인스턴스가 인스턴스화되지 않았거나 일종의 전역 상태를 유지할 때 호출해야하는 클래스 메서드가 필요한 경우 정적이 좋은 생각입니다. 그러나 일반적으로 멤버를 비 정적 상태로 만드는 것이 좋습니다.
메소드와 클래스에 대해 생각해야합니다.
마지막 두 개가 '예'이면 메서드 / 클래스가 정적이어야합니다.
가장 많이 사용되는 예는 아마도 Math
클래스 . 모든 주요 OO 언어에는이 기능이 있으며 모든 메서드는 정적입니다. 인스턴스를 만들지 않고도 언제 어디서나 사용할 수 있어야하기 때문입니다.
또 다른 좋은 예는 Reverse()
C # 의 메서드입니다.
이것은Array
클래스 . 배열의 순서를 반대로합니다.
암호:
public static void Reverse(Array array)
모든 배열이 Array 클래스의 인스턴스이기 때문에 아무것도 반환하지 않으며 배열이 반전됩니다.
새 메서드를 private static으로 만드는 한 주요 변경 사항은 아닙니다. 실제로 FxCop은 다음 정보와 함께이 지침을 규칙 ( http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx ) 중 하나로 포함합니다 .
메서드를 정적으로 표시하면 컴파일러는 이러한 멤버에 가상이 아닌 호출 사이트를 내 보냅니다. 비가 상 호출 사이트를 내 보내면 런타임시 각 호출에 대해 현재 개체 포인터가 null이 아닌지 확인하지 못합니다. 이것은 성능에 민감한 코드에 대해 측정 가능한 성능 향상을 가져올 수 있습니다. 경우에 따라 현재 개체 인스턴스에 액세스하지 못하는 것은 정확성 문제를 나타냅니다.
즉, David Kean의 첫 번째 의견은 이것이 성능 향상에 관한 것보다 실제로 정확하다는 것에 대해 더 간결하게 요약합니다.
이 규칙은 성능 문제로 분류되지만 메서드를 정적으로 만드는 성능 향상은 약 1 %에 불과합니다. 오히려 다른 인스턴스 멤버를 사용하지 않아 멤버가 불완전하거나 버그를 나타낼 수있는 정확성 문제입니다. 메서드를 정적 ( Visual Basic의 경우 Shared )으로 표시하면 인스턴스 상태를 건드리지 않으려는 의도가 명확 해집니다.
어떤 이유로 비 정적으로 만들어진 본질적으로 정적 인 메서드는 단순히 성가시다. 재치 :
은행에 전화하여 잔액을 요청합니다.
그들은 내 계좌 번호를 묻습니다.
그럴 수 있지. 인스턴스 방법.
은행에 전화하여 우편 주소를 물어 봅니다.
그들은 내 계좌 번호를 묻습니다.
WTF? 실패-정적 방법이어야합니다.
나는 일반적으로 순수한 기능의 기능적 관점에서 본다. 인스턴스 메서드 여야합니까? 그렇지 않은 경우 사용자가 현재 인스턴스의 상태를 변경하지 않고 변수를 전달하도록 강제하는 것이 좋습니다. (음, 여전히 상태를 엉망으로 만들 수는 있지만 요점은 의도적으로 그렇게하지 않는 것입니다.) 저는 일반적으로 인스턴스 메서드를 공용 멤버로 디자인하고 개인 멤버를 정적으로 만들기 위해 최선을 다합니다. 필요한 경우 나중에 다른 클래스로 더 쉽게 추출 할 수 있습니다.
이 경우 메서드를 정적 또는 유틸리티 라이브러리로 이동하는 경향이 있으므로 "객체"개념과 "클래스"개념을 혼합하지 않습니다.