2009-06-02 9 views
26

は私の短縮抽象クラスである:ここではCで内部保護されたプロパティを作成する方法は?ここ

abstract class Report { 

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

は、派生クラスである:

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を呼び出すことができることができるようにしたいです派生クラスによってのみ設定できるようにします。私はHeadersを内部にしてみましたが、protectedは内部よりも制限的ではありません。ヘッダーを内部にし、その設定されたアクセサを保護して内部にする方法はありますか?

私はアクセス修飾子を大雑把に悪用しているような気がするので、どんなデザインの助けでも大いに感謝します。

+0

コードが正しくコンパイルされます。 – Noldorin

+3

@ Noldorin:保護内部は保護されているか内部です。 –

+0

@Mehrdad:はい、私はそれを知っていました。ポイントは何ですか? – Noldorin

答えて

16

getterを公開する際に何が問題になっていますか?あなたは

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

としてプロパティを宣言した場合、それはあなたが望むの基準のすべてを満たしている:アセンブリのすべてのメンバーには、プロパティを取得することができ、かつ唯一の派生クラスは、それを設定することができます。もちろん、アセンブリの外のクラスでもプロパティを取得できます。そう?

あなたが本当に公になく、あなたのアセンブリ内のプロパティを公開する必要がありますが、場合は、それを行うための別の方法は、別のプロパティを作成することです:

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

確かに、それはそのI_プレフィックスと名前を飾る醜いです。しかし、それは奇妙なデザインのようなものです。内部のプロパティで名前を変更するいくつかの種類の名前を行うことは、自分自身(または他の開発者)が使用しているプロパティが正統でないことを思い出させる方法です。また、後でこのような混在アクセシビリティが実際にあなたの問題に適切な解決策ではないと判断した場合は、修正するプロパティが分かります。

+2

'protected'プロパティの型が' string'のような 'public'である場合にのみ機能します。 '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

一般的な考えでは、一部のメンバーを保護された内部にすることはできません。

そして、自分のものを含めて多くの人が望むように、あなたは1行でそうすることはできないが、その賢明さは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

あなたは内部の明示的な実装されるインタフェースを使用できます。今、あなたは正確に何をしたいでなければなりませんiReportはが定義されているアセンブリ内の内部アクセスを取得

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; 
    } 
} 

を。

インターフェイスを明示的に実装することは、よく知られている方法ではありませんが、多くの問題を解決します。

3

CLRは、保護されたAND内部(ファミリとアセンブリのアクセシビリティとして知られています)の概念をサポートしています.C#は、この概念を実装/公開してください。 C#のは、おそらく以下のことができなければならない:INTERSECT必要がありそう

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

/ANDプロパティのセッターのための両方の可視性修飾子を、あなたが同じアセンブリ内の任意の場所からヘッダを読みますが、同じアセンブリ内に派生クラスから、それを設定することができます。

+0

CLRはprotected AND internal(ファミリとアセンブリのアクセシビリティと呼ばれる)の概念をサポートしています。上記の私の答えは、C#がこの概念を実装/公開し、提案された構文をそのまま解釈することを示唆しています。私は内部修飾子をプロパティに、保護された修飾子を設定子に付けます(setterには両方とも "protected internal"を置くのと同じではありません)。コメントしてくれてありがとう、私はこのアイデアを強調し、将来の混乱を避けるために私の答えを編集しました。 –

+0

これは何らかの形でサポートすべきです...しかし、私はそれがここにあるのが好きではないと確信しています...内部および保護されたコンストラクタを提案しようとしますか?ライブラリ(アセンブリ)からのみアクセスし、他のライブラリの派生型からはアクセスしないでください。おそらく、「保護された内部」修飾子と「内部保護された」修飾子が異なる場合があります。したがって、第2の意味は、それが「内部」であり、次に「保護」されていることを意味します。オリジナルとは、派生クラス(「保護された」)でも内部的にも(現在のように)あらゆる場所で利用可能であることを意味します。 – Maxim

1

C#7.2以降には、構造体private protectedlink)があります。フィールドからの読み込みは許可されません(したがって、OPが意図しているとおりに正確に行うことはできませんが)。

+0

'internal'と組み合わせて使用​​すると、実際に読み込みを許可することができます:' internal override string [] Headers {get {return headers; }プライベートプロテクションセット{ヘッダー=値; }} 'は内部のみの読み取りと内部および保護のみの書き込みとなります。他の組み合わせも可能です。 –

関連する問題