내부 클래스에서 공개 메소드를 사용하는 이유는 무엇입니까?


250

프로젝트 중 하나에 다음과 같은 코드가 많이 있습니다.

internal static class Extensions
{
    public static string AddFoo(this string s)
    {
        if (s == null)
        {
            return "Foo";
        }

        return $({s}Foo);
    }
}

"나중에 유형을 공개하는 것이 더 쉬운 것"이외의 다른 명백한 이유가 있습니까?

나는 그것이 매우 이상한 가장자리 케이스 (Silverlight에서의 반사)에서만 중요하거나 전혀 그렇지 않다고 생각합니다.


1
내 경험상, 그것은 정상적인 습관입니다.
phoog

2
@phoog, 알았어. 그러나 왜 이것이 일반적인 관행입니까? 아마도 많은 방법을 내부로 변경하는 것이 더 쉬울까요? 빠른 수정-> 대신 내부 유형을 표시 하시겠습니까?
bopapa_1979

그것이 내가 항상 가정했던 것입니다. 그러나 잘 생각한 분석은 없지만 답변을 게시하지 않은 이유입니다.
phoog

2
Eric Lippert의 대답은 내 생각을 잘 요약하고 내 두뇌에 숨어있는 길을 찾으려고하는 무언가를 제시합니다. 인터페이스 멤버의 암시 적 구현은 공개되어야합니다.
phoog

그 방법이 같지 return s + "Foo";않습니까? +운영자는 null 또는 빈 문자열에 대해 상관하지 않는다.
Mikkel R. Lund

답변:


419

업데이트 :이 질문은 2014 년 9 월 내 블로그의 주제였습니다 . 좋은 질문 감사합니다!

컴파일러 팀 자체 내에서도이 질문에 대해 상당한 논쟁이 있습니다.

우선, 규칙을 이해하는 것이 현명합니다. 클래스 또는 구조체의 공용 멤버 는 포함 형식에 액세스 할 수있는 모든 항목에 액세스 할 수있는 멤버입니다 . 따라서 내부 클래스의 공개 멤버는 사실상 내부입니다.

이제 내부 클래스가 주어지면 어셈블리에서 액세스하려는 멤버를 공개 또는 내부로 표시해야합니까?

내 의견은 : 그런 회원들을 공개로 표시하십시오.

"public"을 사용하여 "이 멤버는 구현 세부 정보가 아닙니다"를 의미합니다. 보호 된 멤버는 구현 세부 사항입니다. 파생 된 클래스 작업을 수행하는 데 필요한 내용이 있습니다. 내부 멤버는 구현 세부 사항입니다. 이 어셈블리 내부의 다른 무언가가 올바르게 작동하려면 멤버가 필요합니다. 공용 구성원은 "이 구성원은이 개체에서 제공하는 주요 문서화 된 기능을 나타냅니다."라고 말합니다.

기본적으로 내 태도는 :이 내부 수업을 공개 수업으로 만들기로 결정했다고 가정 해 봅시다. 이를 위해 클래스의 접근성이라는 것을 정확히 변경하고 싶습니다 . 내부 클래스를 공개 클래스로 바꾸는 것이 내부 멤버도 공개 멤버로 바꿔야 한다는 것을 의미하는 경우 해당 멤버는 클래스 의 공개 영역 의 일부였으며 처음에는 공개되어야했습니다.

다른 사람들은 동의하지 않습니다. 멤버 선언을 한눈에보고 내부 코드에서만 호출되는지 여부를 즉시 알고 싶다는 조건이 있습니다.

불행히도, 그것이 항상 잘 작동하는 것은 아닙니다. 예를 들어, 내부 인터페이스를 구현하는 내부 클래스는 클래스의 공용 영역의 일부 이므로 구현 멤버를 public으로 표시해야합니다 .


11
이 답변이 마음에 듭니다. 가능한 한 많이 문서화하는 코드 작성에 대한 저의 태도에 잘 맞으며, 특히 다른 팀원이 컨벤션을 이해하는 경우 범위는 의도를 방송하는 좋은 방법입니다.
bopapa_1979

10
내가 말하고 싶은 말을 할 수는 있지만 내가 할 수있는 것보다 훨씬 더 잘 공식화했습니다 (인터페이스 각도를 가져 오는 것도 암시 적 멤버 구현의 경우에만 해당됩니다).
phoog

2
인터페이스 부분은 중요합니다. 내부를 사용하여 인터페이스 메소드를 구현하는 것은 불가능합니다. 공개 또는 명시 적 인터페이스 선언입니다. 따라서 public이라는 단어에는 두 가지 의미가 있습니다.
Michael Stum

8
아이디어적인 관점에서 당신이 선호하는 주장 public은 매우 설득력이 있습니다. 그러나 "항상 잘 작동하지는 않습니다 ..."가 특히 강력하다는 것을 알았습니다. 일관성을 잃으면 "한 눈에 볼 수있는"혜택이 평가 절하됩니다. internal이런 식으로 사용 한다는 것은 때때로 잘못된 직관을 의도적으로 구축하는 것을 의미합니다. 가장 올바른 직감을 갖는 것은 프로그래밍에있어 끔찍한 일입니다.
Brian

3
블로그 게시물의 중요한 인용문 : "내 조언은 팀 간의 문제에 대해 토론하고 결정을 내린 다음이를 고수하는 것입니다."
bopapa_1979

17

클래스가 internal인 경우 메서드를 표시하는지 internal또는에 표시하는지 여부는 접근성 관점에서 중요하지 않습니다 public. 그러나 클래스가 있었다면 사용할 유형을 사용하는 것이 여전히 좋습니다 public.

일부는이에서 전환을 용이하게했다있는 반면 internalpublic. 또한 방법 설명의 일부로 사용됩니다. Internal메소드는 일반적으로 자유로운 액세스에 대해 안전하지 않은 public것으로 간주되는 반면, 메소드는 (대부분) 무료 게임으로 간주됩니다.

사용하여 internal또는 public당신은에서와 public클래스, 당신은 당신이 또한 클래스를 만들기 위해 필요한 작업 완화하면서 액세스의 스타일이 예상되는 어떤 통신 할 수 있도록 public미래를.


나는 좋은 API를 만들고 의도 한 소비자가 내가 원하는 것을 할 수있게하면서 가능한 모든 것을 최대한 제한하는 경향이있다. 또한 수업이 공개 된 경우처럼 회원을 표시하는 데 참여합니다. 보다 구체적으로, 나는 항상 안전하다고 생각하는 경우에만 회원을 공개로 표시합니다. 그렇지 않으면 나중에 다른 사람에게 클래스를 공개로 표시하면 (발생하는 경우) 안전하지 않은 멤버가 노출 될 수 있습니다.
bopapa_1979

@ 에릭 : 준비가 될 때까지 방법의 안전성을 결정하지 않으려면 괜찮지 만 안전한 것으로 간주되는 방법 만 참조하면 노출이 없습니다.
Guvante

10

나는 종종 내부 클래스 대신 내부 클래스에서 내 메소드를 표시합니다 .a) 실제로 중요하지 않습니다 .b) 내부에서 메소드가 의도적으로 내부임을 나타냅니다. 따라서 내부 메서드가있는 경우 내부 메서드를 공개로 변경하기 전에 내부 이유를 이해해야하지만 내부 클래스에서 공개 메서드를 처리하는 경우 왜 그 이유에 대해 생각해야합니다. 클래스는 각 메소드가 내부적 인 이유와 반대로 내부입니다.


답변 해주셔서 감사합니다. :)하지만, 코딩 할 때 내가 고집이 "모든"문제를 주장하는 경향이
bopapa_1979을

1
당신은 올바른 에릭입니다. 내 대답의 나머지 부분이 약간 사용 되었기를 바랍니다. 에릭 리퍼의 대답은 제가 표현하려고했던 것이지만 그는 훨씬 더 잘 설명했습니다.
Ɖiamond ǤeezeƦ

8

"나중에 유형을 공개하는 것이 더 쉬운가요?" 그렇습니다.

범위 지정 규칙은 방법은 전용으로 볼 수 있다는 것을 의미 internal정말 방법이 표시됩니다 여부를 중요하지 않습니다 - 그래서 publicinternal.

명심해야 할 한 가지 가능성은 클래스 공개되었고 나중에 변경되었으며 internal개발자가 모든 메소드 액세스 가능성 수정자를 변경하지 않았다는 것입니다.


1
명백한 "공공 계급이 내부가되었다"는 시나리오를 +1했습니다.
bopapa_1979

8

경우에 따라 내부 유형에 공용 인터페이스가 구현되어 해당 인터페이스에 정의 된 모든 메소드를 여전히 공용으로 선언해야 할 수도 있습니다.



0

internal멤버는 동일한 어셈블리 내에서만 액세스 할 수 있습니다. 해당 어셈블리의 다른 클래스는 액세스 할 수있는 internal public멤버 만 접근 a를 할 수 없을 것 private또는 protected회원 internal여부.


그러나 메소드 internal대신에 메소드가 표시되면 public가시성이 변경되지 않습니다. 나는 그것이 OP가 요구하는 것이라고 생각합니다.
오디드

1
@ zapthedingbat-게시물은 사실 정확하지만 실제로 질문에 대답하고 있습니까?
오디드

1
문제는 왜 그런 식으로 표시해야 하는가입니다. 나는 범위의 기본을 이해합니다. 그래도 감사합니다!
bopapa_1979

0

나는 실제로 오늘 이것으로 고투했다. 지금까지 나는 internal클래스가 internal특히 엔터프라이즈 개발에서 단순히 나쁜 코딩이나 게으름으로 여겨 지면 메소드에 모두 표시해야한다고 말했다 . 그러나 클래스를 서브 클래스 화하고 public메소드 중 하나를 재정의해야했습니다.

internal class SslStreamEx : System.Net.Security.SslStream
{
    public override void Close()
    {
        try
        {
            // Send close_notify manually
        }
        finally
        {
            base.Close();
        }
    }
}

에릭 리퍼 트가 말한 것처럼 이 방법은 반드시 있어야 public하고 방법을 설정해야 할 논리적 근거가 없다고 생각 internal했다.

지금까지 나는 그것에 대해 생각하는 것을 결코 멈추지 않았고 방금 그것을 받아 들였지만 Eric의 게시물을 읽은 후에 정말 생각하고 많은 고의를 기울인 후에 많은 의미가 있습니다.


0

차이가 있습니다. 프로젝트에서 많은 클래스를 내부적으로 만들었지 만 다른 어셈블리에서 단위 테스트를 수행하고 어셈블리 정보에서 InternalsVisibleTo를 사용하여 UnitTest 어셈블리가 내부 클래스를 호출 할 수 있도록했습니다. 내부 클래스에 내부 생성자가 있으면 어떤 이유로 단위 테스트 어셈블리에서 Activator.CreateInstance를 사용하여 인스턴스를 만들 수 없습니다. 그러나 생성자를 public으로 변경했지만 클래스가 여전히 내부라면 잘 작동합니다. 그러나 나는 이것이 매우 드문 경우라고 생각합니다 (에릭처럼 원래 게시물에서 반사 :).


0

나는 이것에 대한 추가 의견이 있다고 생각합니다. 처음에는 내부 클래스에서 무언가를 대중에게 선언하는 것이 어떻게 의미가 있는지 궁금했습니다. 그런 다음 나중에 수업을 공개로 변경하기로 결정하면 좋을 것이라고 읽었습니다. 진실. 따라서 내 마음에 패턴이 형성되었습니다 . 현재 동작을 변경하지 않으면 허용하고 현재 코드 상태에서 의미가 없으며 아프지 않은 것을 허용하십시오. 클래스 선언을 변경하십시오.

이처럼 :

public sealed class MyCurrentlySealedClass
{
    protected void MyCurretlyPrivateMethod()
    {
    }
}

위에서 언급 한 "패턴"에 따르면 이것은 완벽하게 괜찮습니다. 그것은 같은 생각을 따릅니다. private클래스를 상속받을 수 없으므로 메소드 로 작동 합니다. 그러나 sealed제약 조건 을 삭제하면 여전히 유효합니다. 상속 된 클래스는이 방법을 볼 수 있습니다.이 방법은 내가 달성하고자하는 것입니다. 그러나 경고가 나타납니다 : CS0628또는 CA1047. 둘 다 클래스 protected에서 멤버를 선언하지 않습니다 sealed. 또한 나는 무의미하다는 것에 대해 완전한 동의를 얻었습니다 : '봉인 된 클래스의 보호 된 멤버'경고 (싱글 톤 클래스)

그래서이 경고와 토론이 연계 된 후에, 나는 내부 클래스에서 모든 것을 내부 또는 이하로 만들기로 결정했습니다. 왜냐하면 그것은 더 많은 종류의 사고에 부합하기 때문입니다. 우리는 다른 "패턴"을 섞지 않습니다.


에릭 리퍼 트 ​​(Eric Lippert)는 이렇게 말했다. 그의 기사는 확실히 읽을 가치가 있습니다.
bopapa_1979
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.