2009-06-02 1 views
26
여기

내 단축 추상 클래스입니다 : 아이디어는C#에서 속성을 보호하고 내부로 만드는 방법은 무엇입니까?

class OnlineStatusReport : Report { 

    static string[] headers = new string[] { 
     "Time", 
     "Message" 
    } 

    protected internal override string[] Headers { 
     get { return headers; } 
     protected set { headers = value; } 
    } 

    internal OnlineStatusReport() { 
     Headers = headers; 
    } 
} 

, 내가 어디에서 Report.Headers를 호출 할 수 할 수 있도록하려면 다음은

abstract class Report { 

    protected internal abstract string[] Headers { get; protected set; } 
} 

파생 클래스입니다 어셈블리를 만들지 만 파생 클래스 만 설정하도록 허용합니다. Headers를 내부적으로 만들려고했으나 protected는 내부보다 더 제한적이지 않습니다. 헤더를 내부에 만들고 해당 접근자를 보호하고 내부로 만드는 방법이 있습니까?

나는 액세스 수정자를 심하게 오용하고있는 것처럼 느껴 지므로 어떤 디자인 도움도 크게 감사 할 것입니다.

+0

코드가 잘 컴파일됩니다. – Noldorin

+3

@Noldorin : 보호 된 내부는 보호되거나 내부입니다. –

+0

@Mehrdad : 예, 알았습니다. 점은 무엇인가? – Noldorin

답변

16

게터를 공개하는 것이 잘못된 이유는 무엇입니까? 속성을 얻을 수있는 어셈블리의 모든 회원, 만 파생 클래스를 설정할 수 있습니다 당신이

public string[] Headers { get; protected set; } 

로 속성을 선언하면 당신이 원하는 모든 기준을 충족합니다. 물론, 어셈블리 외부의 클래스도 속성을 얻을 수 있습니다. 그래서? 당신이 진정으로 어셈블리 내에서 속성을 노출하지만 공개적으로, 그것을 할 수있는 또 다른 방법은 다른 재산 만드는 것입니다해야하는 경우

는 :

protected string[] Headers { get; set; } 
internal string[] I_Headers { get { return Headers; } } 

물론을, 그 I_ 접두어로 이름을 장식 추한. 그러나 그것은 이상한 디자인의 일종입니다. 내부 재산에 대한 언쟁하는 이름을 쓰는 일은 자신이나 다른 개발자에게 자신이 소유 한 재산이 정통 적이라는 것을 상기시키는 방법입니다. 또한 나중에 이와 같은 혼합 접근성이 문제에 대한 올바른 해결책이 아니라고 결정하면 수정할 속성을 알 수 있습니다.

+2

'protected' 속성의 타입이'public' ('string []'처럼) 일 때만 작동합니다. 'protected' 속성의 유형 자체가'internal' 인 경우 - 컴파일이 메시지와 함께 실패합니다.'일관성없는 접근성 : 속성 유형 'Library.A'는 'Library.OnlineStatusReport.Headers'' 속성보다 접근하기가 어렵습니다. – DarkWalker

28

C#에서는 불가능합니다.

이는 완전성을 위해 IL (패밀리 및 어셈블리 액세스 수정 자)에서 지원됩니다.

+0

컴파일 후 IL 코드를 수정하여 원하는 결과를 얻을 수있는 빌드 후 이벤트 도구가 있습니까? – DarkWalker

6

나는 액세스 한정자를 보호 된 상태로 유지하고 내부 도우미 메서드가 있습니다.

protected override string[] Headers { 
    get { return headers; } // Note that get is protected 
    set { headers = value; } 
} 

internal SetHeadersInternal(string[] newHeaders) 
{ 
    headers = newHeaders; 
} 

하지만 어떻게 든 리팩토링해야하는 것처럼 냄새가납니다. 내부는 모든 것이 어쨌든 어셈블리 내의 다른 모든 것을 사용하는 아주 지저분한 아키텍처로 이어질 수 있기 때문에 항상 쓸모가 있습니다. 물론 예외는 항상 있습니다.

2

일부 회원을 보호하고 내부로 만들 수는 없다는 것은 일반적인 생각입니다.

그리고 나 자신을 포함한 많은 사람들이 원하면 그렇게 할 수 없다는 것이 사실이지만 일부 영리함으로는 100 % 할 수 있습니다.

//Code below is 100% tested 

/* FROM ProtectedAndInternal.dll */ 

namespace ProtectedAndInternal 
{ 
    public class MyServiceImplementationBase 
    { 
     protected static class RelevantStrings 
     { 
      internal static string AppName = "Kickin' Code"; 
      internal static string AppAuthor = "Scott Youngblut"; 
     } 
    } 

    public class MyServiceImplementation : MyServiceImplementationBase 
    { 
     public void PrintProperties() 
     { 
      // WORKS PERFECTLY BECAUSE SAME ASSEMBLY! 
      Console.WriteLine(RelevantStrings.AppAuthor); 
     } 
    } 

    public class NotMyServiceImplementation 
    { 
     public void PrintProperties() 
     { 
      // FAILS - NOT THE CORRECT INHERITANCE CHAIN 
      // Error CS0122: 'ProtectedAndInternal.MyServiceImplementationBase.Relevant' is inaccessible due to its protection level 
      // Console.WriteLine(MyServiceImplementationBase.RelevantStrings.AppAuthor); 
     } 
    } 
} 



/* From AlternateAssemblyService.dll which references ProtectedAndInternal.dll */ 

namespace AlternateAssemblyService 
{ 
    public class MyServiceImplementation : MyServiceImplementationBase 
    { 
     public void PrintProperties() 
     { 
      // FAILS - NOT THE CORRECT ASSEMBLY 
      // Error CS0117: 'ProtectedAndInternal.MyServiceImplementationBase.RelevantStrings' does not contain a definition for 'AppAuthor' 
      // Console.WriteLine(RelevantStrings.AppAuthor); 
     } 
    } 
} 
+0

내부 클래스는 보호 된 내부 용으로 사용하려면 정적이어야합니다. 나는 당신의 아이디어를 사용했지만, 부모 클래스에서 나는 내 "보호 된 내부"멤버에 액세스하는 데 사용했던 내부 클래스의 인스턴스를 가졌다. –

5

당신은 내부 명시 적으로 구현 된 인터페이스를 사용할 수 있습니다

internal interface IReport 
{ 
    string[] Headers { get; } 
} 

abstract class Report : IReport 
{ 
    protected abstract string[] Headers { get; protected set; } 

    string[] IReport.Headers 
    { 
     get { return Headers; } 
    } 
} 

class OnlineStatusReport : Report 
{ 
    static string[] headers = new string[] { "Time", "Message" }; 

    protected internal override string[] Headers 
    { 
     get { return headers; } 
     protected set { headers = value; } 
    } 

    internal OnlineStatusReport() 
    { 
     Headers = headers; 
    } 
} 

지금 정확히 당신이 원하는해야 iReport로 정의되어 어셈블리, 내부 접근 할 수 있습니다.

명시 적으로 인터페이스를 구현하는 것은 잘 알려진 전략은 아니지만 많은 문제를 해결합니다.

3

CLR은 protected AND internal (family-and-assembly 접근성이라고도 함) 개념을 지원하고 C#이 개념을 구현/노출해야합니다. C#을 아마 다음과 같은 허용해야한다 : INTERSECT한다 이렇게

internal string[] Header { get; protected set; } 

/와 속성 setter 모두 가시성 수정과 같은 어셈블리 내 어디에서나 헤더를 읽을 수 있지만 동일한 어셈블리 내에서 파생 된 클래스에서을 설정할 수 .

+0

CLR은 protected AND internal (family-and-assembly 접근성이라고도 함)의 개념을 지원하며 위의 대답은 C#이이 개념을 구현/노출하고 제안 된 구문을 그대로 해석해야한다고 제안합니다. 공지 사항 내부 수정자를 속성에 넣고 보호 된 수식어를 setter에 넣습니다 (setter에 "protected internal"을 둘 다 넣는 것과 같지 않음). 의견을 보내 주셔서 감사 드리며,이 아이디어를 강조하고 미래의 혼동을 피하기 위해 답을 수정했습니다. –

+0

그것은 어떤 식 으로든 지원해야합니다 ...하지만 여기에있는 것이 맘에 들지 않을 것입니다 ... 내부 및 보호 된 생성자를 제안하려고합니까?라이브러리 (어셈블리)에서만 액세스해야하며 다른 라이브러리의 파생 형식에서 액세스하면 안됩니다. 우리는 "보호 된 내부"와 "내부 보호 된"수정자를 다를 수 있습니다. 그래서 두 번째 의미는 그것이 "내부"이고 처음에는 "보호 된"것을 의미합니다. 그리고 원래의 의미는 파생 클래스 ("보호 된") 에서뿐만 아니라 내부적으로도 (현재와 같이) 사용할 수 있음을 의미합니다. – Maxim

1

C# 7.2부터 구조체 private protected (link)이 있습니다. 필드에서 읽는 것을 허용하지 않으므로 (OP가 의도하는 바를 정확하게 수행하지는 못하지만) 전리품을 쓸 가치가 있습니다.

+0

'internal'과 함께 사용하면 실제로 읽을 수 있습니다 :'internal override string [] Headers {get {return headers; } 개인 보호 집합 {headers = value; }}'내부 전용 읽기 및 내부 및 보호 전용 쓰기 것입니다. 다른 조합도 가능합니다. –

관련 문제