문제

실질적인 사용법이 무엇인지 설명해 주시겠습니까? internal C#의 키워드?

나는 그것을 알고있다 internal 수정자는 현재 어셈블리에 대한 액세스를 제한하지만 언제 어디에서 사용해야합니까?

도움이 되었습니까?

해결책

동일한 어셈블리 내의 다른 많은 클래스에서 액세스하려는 유틸리티 또는 도우미 클래스/방법이지만 다른 어셈블리의 코드에 액세스 할 수 없도록하려고합니다.

에서 MSDN (Archive.org를 통해) :

내부 액세스의 일반적인 사용은 구성 요소 기반 개발에 있습니다.이 그룹은 컴포넌트 그룹이 나머지 응용 프로그램 코드에 노출되지 않고 개인 방식으로 협력 할 수 있기 때문입니다. 예를 들어, 그래픽 사용자 인터페이스를 구축하기위한 프레임 워크는 내부 액세스를 사용하여 멤버를 사용하여 협력하는 컨트롤 및 양식 클래스를 제공 할 수 있습니다. 이 멤버는 내부이므로 프레임 워크를 사용하는 코드에 노출되지 않습니다.

당신은 또한 내부 수정자를 InternalsVisibleTo 어셈블리 레벨 속성 대상 어셈블리 내부 클래스에 특별한 액세스 권한이 부여 된 "친구"어셈블리를 만들기위한 속성.

이는 단위 테스트 어셈블리 생성에 유용 할 수 있으며, 그 후 어셈블리의 내부 멤버를 호출하여 테스트 할 수 있습니다. 물론 다른 어셈블리는이 수준의 액세스 권한이 부여되지 않으므로 시스템을 해제하면 캡슐화가 유지됩니다.

다른 팁

Bob이 Big ImportantClass가 필요하다면 Bob은 프로젝트 A를 소유 한 사람들에게 Big ImportantClass가 자신의 요구를 충족시키기 위해 작성하고 자신의 요구를 충족 시키도록 테스트하고 자신의 요구를 충족시키는 것으로 문서화되며 프로세스를 작성하도록 보장하기 위해 가입하도록해야합니다. 더 이상 자신의 요구를 충족시키지 못하도록 결코 바뀌지 않도록하기 위해 마련 될 것입니다.

클래스가 내부 인 경우 해당 프로세스를 거치지 않아도되므로 프로젝트 A의 예산이 다른 것에 소비 할 수 있습니다.

내부의 요점은 밥에게는 삶을 어렵게 만드는 것이 아닙니다. 그것은 비싼 약속 프로젝트 A가 기능, 수명, 호환성 등에 대해 무엇을 만들고 있는지 제어 할 수 있다는 것입니다.

내부를 사용해야하는 또 다른 이유는 이진을 난독 화하는 경우입니다. Obfuscator는 모든 내부 클래스의 클래스 이름을 스크램블하는 것이 안전하다는 것을 알고 있지만 공개 클래스의 이름은 기존 참조를 중단 할 수 있기 때문에 스크램블 할 수 없습니다.

복잡한 기능을 단순한 공개 API에 캡슐화하는 DLL을 작성하는 경우 공개적으로 노출되지 않는 클래스 멤버에 "내부"가 사용됩니다.

복잡성을 숨기고 (일명 캡슐화) 품질 소프트웨어 엔지니어링의 주요 개념입니다.

내부 키워드는 관리가 아닌 코드를 통해 래퍼를 만들 때 많이 사용됩니다.

dllimport를하려는 C/C ++ 기반 라이브러리가 있으면 이러한 기능을 클래스의 정적 기능으로 가져 와서 내부로 만들 수 있으므로 사용자는 원래 API가 아닌 래퍼에만 액세스 할 수 없으므로 원래 API에만 액세스 할 수 없습니다. 무엇이든 엉망입니다. 정적 인 기능은 조립품의 모든 곳에서 사용할 수 있으며 필요한 다중 래퍼 클래스를 위해 사용할 수 있습니다.

Mono.Cairo를 살펴볼 수 있습니다.이 접근법을 사용하는 카이로 라이브러리 주변의 포장지입니다.

"당신이 할 수있는대로 엄격한 수정 자로 사용"규칙에 따라 다른 클래스의 방법에 액세스하는 데 필요한 모든 곳에서 내부를 사용합니다. 다른 어셈블리에서 명시 적으로 액세스해야 할 때까지.

어셈블리 인터페이스는 일반적으로 클래스 인터페이스의 합보다 더 좁기 때문에 사용하는 곳이 많이 있습니다.

나는 내부가 훨씬 많이 사용되는 것을 발견했다. 당신은 실제로 다른 소비자에게하지 않을 특정 클래스에만 특정 기능을 노출해서는 안됩니다.

이것은 내 의견으로는 인터페이스를 깨뜨리고 추상화를 깨뜨립니다. 이것은 절대로 사용해서는 안되지만 더 나은 솔루션은 다른 클래스에 리팩터를 리팩터링하거나 가능한 경우 다른 방식으로 사용하는 것입니다. 그러나 이것이 항상 가능하지는 않습니다.

문제를 일으킬 수있는 이유는 다른 개발자가 귀하와 동일한 어셈블리에서 다른 클래스를 구축하는 것으로 기소 될 수 있기 때문입니다. 내부를 갖는 것은 추상화의 명확성을 줄이고 오용하면 문제를 일으킬 수 있습니다. 공개 한 것과 같은 문제가 될 것입니다. 다른 개발자가 구축 한 다른 클래스는 외부 클래스와 마찬가지로 여전히 소비자입니다. 클래스 추상화 및 캡슐화는 외부 클래스를 보호/보호하기위한 것이 아니라 모든 클래스를위한 것입니다.

또 다른 문제는 많은 개발자들이 할 것이라는 것입니다 생각한다 그들은 어셈블리의 다른 곳에서 그것을 사용하고 당시에는 필요하지 않더라도 어쨌든 내부로 표시해야 할 수도 있습니다. 그런 다음 다른 개발자는 테이크를 위해 거기에 있다고 생각할 수 있습니다. 일반적으로 결정적인 필요가있을 때까지 개인 표시를 원합니다.

그러나이 중 일부는 주관적 일 수 있으며, 절대 사용해서는 안된다고 말하지는 않습니다. 필요할 때만 사용하십시오.

내가 기억할 수없는 블로그에서 다른 날, 어쩌면 일주일에 흥미로운 것을 보았습니다. 기본적으로 나는 이것에 대한 신용을받을 수 없지만 유용한 응용 프로그램이있을 수 있다고 생각했습니다.

다른 어셈블리에서 추상적 인 수업을보고 싶었지만 누군가가 상속 받기를 원하지 않습니다. 봉인 된 것은 이유 때문에 추상적이기 때문에 작동하지 않습니다. 어셈블리의 다른 클래스는 상속합니다. 다른 어셈블리 어딘가에 부모 수업을 선언 할 수 있기 때문에 개인은 작동하지 않습니다.

namespace Base.Assembly
{
  public abstract class Parent
  {
    internal abstract void SomeMethod();
  }

  //This works just fine since it's in the same assembly.
  public class ChildWithin : Parent
  {
    internal override void SomeMethod()
    {
    }
  }
}

namespace Another.Assembly
{
  //Kaboom, because you can't override an internal method
  public class ChildOutside : Parent
  {
  }

  public class Test 
  { 

    //Just fine
    private Parent _parent;

    public Test()
    {
      //Still fine
      _parent = new ChildWithin();
    }
  }
}

보시다시피, 누군가가 상속받지 않고도 부모 클래스를 효과적으로 사용할 수 있습니다.

이 예제에는 두 개의 파일이 포함되어 있습니다 : Assembly1.cs 및 Assembly2.cs. 첫 번째 파일에는 내부 기본 클래스 인 BaseClass가 포함되어 있습니다. 두 번째 파일에서베이스 클래스를 인스턴스화하려는 시도는 오류가 발생합니다.

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

이 예에서는 예 1에서 사용한 것과 동일한 파일을 사용하고베이스 클래스의 접근성 레벨을 변경하십시오. 공공의. 또한 멤버 intm의 접근성 수준을 변경하십시오. 내부. 이 경우 클래스를 인스턴스화 할 수 있지만 내부 멤버에 액세스 할 수는 없습니다.

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

원천: http://msdn.microsoft.com/en-us/library/7c5ka91b(vs.80).aspx

내부 구성원의 매우 흥미로운 사용 - 내부 멤버가 선언 된 어셈블리에만 제한되는 것은 "친구"기능을 어느 정도까지 얻는 것입니다. 친구 회원은 그 어셈블리 외부의 다른 어셈블리에만 보이는 것입니다. C#에는 친구를 지원하지는 않지만 CLR은 그렇지 않습니다.

당신이 사용할 수있는 InternalSvisibleToattribute 친구 어셈블리를 선언하려면 친구 어셈블리 내의 모든 참조는 선언 어셈블리의 내부 구성원을 친구 어셈블리의 범위 내에서 대중으로 취급합니다. 이것의 문제는 모든 내부 구성원이 보이 었다는 것입니다. 당신은 선택하고 선택할 수 없습니다.

InternalSvisibleto에 잘 활용되는 것은 다양한 내부 구성원을 단위 테스트 어셈블리에 노출 시켜서 회원을 테스트하기 위해 복잡한 반사 작업에 대한 요구를 제거하는 것입니다. 볼 수있는 모든 내부 구성원은 그다지 문제가되지는 않지만이 접근 방식을 취하면 클래스 인터페이스가 상당히 크게 막히고 선언 어셈블리 내에서 캡슐화를 망칠 수 있습니다.

현재 어셈블리의 범위 내에서 액세스 할 수있는 방법, 클래스 등이있는 경우.

예를 들어, DAL은 ORM을 가질 수 있지만 객체는 비즈니스 계층에 노출되어서는 안됩니다. 모든 상호 작용은 정적 메소드를 통해 수행되어 필요한 매개 변수를 전달해야합니다.

두 가지 종류의 회원이 있습니다.

  • 공공 표면: 외부 어셈블리 (공개, 보호 및 내부 보호)에서 볼 수 있습니다 : 발신자는 신뢰할 수 없으므로 매개 변수 검증, 메소드 문서 등이 필요합니다.
  • 개인 표면: 외부 어셈블리 (개인 및 내부 또는 내부 클래스)에서 보이지 않음 : 발신자는 일반적으로 신뢰할 수 있으므로 매개 변수 검증, 메소드 문서 등을 생략 할 수 있습니다.

노이즈 감소는 유형이 적을수록 라이브러리가 더 간단합니다. 탬퍼 교정 / 보안은 또 다른 것입니다 (반사가 이길 수 있지만).

내부 클래스를 사용하면 어셈블리의 API를 제한 할 수 있습니다. API를 더 간단하게 이해할 수있는 것과 같은 이점이 있습니다.

또한 어셈블리에 버그가 존재하는 경우 수정이 중단 변경을 도입 할 가능성이 적습니다. 내부 수업이 없으면 클래스의 공개 회원을 변경하는 것이 깨진 변화가 될 것이라고 가정해야합니다. 내부 클래스를 사용하면 공개 멤버를 수정하면 어셈블리의 내부 API (및 InternalSvisibleto 속성에 참조 된 어셈블리) 만 깨지는 것으로 가정 할 수 있습니다.

나는 수업 수준과 어셈블리 수준에서 캡슐화하는 것을 좋아합니다. 이것에 동의하지 않는 사람들이 있지만 기능이 사용할 수 있다는 것을 아는 것이 좋습니다.

데이터 백엔드에 LINQ-to-SQL을 사용하는 프로젝트가 있습니다. 비즈와 데이터의 두 가지 기본 공간이 있습니다. LINQ 데이터 모델은 데이터에 살고 있으며 "내부"로 표시됩니다. Biz 네임 스페이스에는 LINQ 데이터 클래스를 감싸는 공개 클래스가 있습니다.

그래서 있습니다 Data.Client, 그리고 Biz.Client; 후자는 데이터 객체의 모든 관련 특성을 드러냅니다.

private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }

BIZ 물체에는 개인 생성자 (공장 방법의 사용을 강요하기 위해)와 다음과 같은 내부 생성자가 있습니다.

internal Client(Data.Client client) {
    this._client = client;
}

이는 라이브러리의 모든 비즈니스 클래스에서 사용할 수 있지만 프론트 엔드 (UI)에는 데이터 모델에 직접 액세스 할 수있는 방법이 없으므로 비즈니스 계층이 항상 중개자 역할을합니다.

제가 정말로 사용한 것은 이번이 처음입니다 internal 많이, 그리고 그것은 매우 유용하다는 것을 증명합니다.

수업 구성원을 만드는 것이 합리적 인 경우가 있습니다. internal. 수업이 어떻게 인스턴스화되는지 통제하려는 경우 한 가지 예일 수 있습니다. 수업 인스턴스를 만들기위한 일종의 공장을 제공한다고 가정 해 봅시다. 생성자를 만들 수 있습니다 internal, 공장 (동일한 어셈블리에 상주하는)이 클래스의 인스턴스를 만들 수 있지만 해당 어셈블리 외부의 코드는 할 수 없습니다.

그러나 나는 수업이나 회원을 만드는 시점을 볼 수 없습니다. internal 구체적인 이유없이 public, 또는 private 특정한 이유없이.

내부 키워드를 사용한 유일한 것은 내 제품의 라이센스 확인 코드입니다 ;-)

내부 키워드를 사용하는 것은 어셈블리 사용자의 구체적인 구현에 대한 액세스를 제한하는 것입니다.

객체 구성을위한 공장 또는 기타 중앙 위치가있는 경우, 어셈블리 사용자는 공개 인터페이스 또는 추상 기본 클래스 만 처리하면됩니다.

또한 내부 생성자를 사용하면 다른 공개 클래스가 인스턴스화되는 위치와시기를 제어 할 수 있습니다.

어떻게이 방법 : 일반적으로 어셈블리의 외부 사용자에게 목록 객체를 노출하지 않고 오히려 ienumerable을 노출하는 것이 좋습니다. 그러나 배열 구문과 다른 모든 목록 메소드를 얻기 때문에 어셈블리 내부의 목록 개체를 사용하는 것이 훨씬 쉽습니다. 따라서 일반적으로 어셈블리 내부에서 사용할 목록을 노출시키는 내부 속성이 있습니다.

이 접근법에 대한 의견을 환영합니다.

정의 된 모든 클래스를 명심하십시오 public 누군가가 프로젝트 네임 스페이스를 볼 때 Intellisense에 자동으로 표시됩니다. API 관점에서 볼 때 프로젝트의 사용자에게 사용할 수있는 클래스 만 표시하는 것이 중요합니다. 사용 internal 그들이 볼 수없는 것을 숨기는 키워드.

당신의 경우 Big_Important_Class 프로젝트 A의 경우 프로젝트 외부에서 사용하기위한 것이므로 표시해서는 안됩니다. internal.

그러나 많은 프로젝트에서는 종종 프로젝트 내에서만 사용하기위한 수업이 있습니다. 예를 들어, 인수를 매개 변수화 된 스레드 호출에 보유하는 클래스가있을 수 있습니다. 이 경우, 당신은 그것들을 다음과 같이 표시해야합니다 internal 의도하지 않은 API로부터 자신을 보호하는 것 외에 다른 이유가 없다면 도로 아래로 변합니다.

아이디어는 도서관을 설계 할 때 외부에서 사용하기위한 클래스 만 (도서관의 클라이언트에 의해) 공개되어야한다는 것입니다. 이렇게하면 수업을 숨길 수 있습니다

  1. 향후 릴리스에서 변경 될 가능성이 높습니다 (공개 된 경우 클라이언트 코드를 위반할 것입니다).
  2. 고객에게는 쓸모가 없으며 혼란을 유발할 수 있습니다
  3. 안전하지 않습니다 (따라서 부적절한 사용은 도서관을 꽤 심하게 파괴 할 수 있습니다)

등.

내부 요소를 사용하는 것보다 실내 솔루션을 개발하는 경우 일반적으로 고객이 귀하와 지속적으로 접촉하거나 코드에 액세스 할 수 있기 때문에 중요하지 않습니다. 그래도 도서관 개발자에게는 상당히 중요합니다.

객체 지향 패러다임에 깨끗하게 맞지 않는 클래스 나 방법이있는 경우, 위험한 일을하는 데있어 다른 클래스와 방법에서 호출해야하며 다른 사람이 사용하고 싶지 않은 경우 .

public class DangerousClass {
    public void SafeMethod() { }
    internal void UpdateGlobalStateInSomeBizarreWay() { }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top