31

これが私の短縮された抽象クラスです:

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ましたが、保護は内部よりも制限的であるとは見なされません。ヘッダーを内部にし、そのセットアクセサーを保護して内部にする方法はありますか?

アクセス修飾子をひどく誤用しているような気がするので、デザインの助けをいただければ幸いです。

4

8 に答える 8

32

C#では不可能です。

完全を期すために、これはIL(ファミリおよびアセンブリアクセス修飾子)でサポートされています。

于 2009-06-02T18:26:27.943 に答える
19

ゲッターを公開することの何が問題になっていますか?プロパティを次のように宣言した場合

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

必要なすべての基準を満たしています。アセンブリのすべてのメンバーがプロパティを取得でき、派生クラスのみがプロパティを設定できます。もちろん、アセンブリ外のクラスもプロパティを取得できます。それで?

アセンブリ内でプロパティを公開する必要があるが、公開する必要がない場合は、別の方法で別のプロパティを作成します。

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

確かに、そのI_接頭辞で名前を飾るのは醜いです。しかし、それは一種の奇妙なデザインです。内部プロパティに対してある種の名前マングリングを行うことは、使用しているプロパティが非正統的であることを自分自身(または他の開発者)に思い出させる方法です。また、後でこのようなアクセシビリティの混合が問題の正しい解決策ではないと判断した場合は、修正するプロパティがわかります。

于 2009-06-02T20:01:24.417 に答える
6

アクセス修飾子を保護されたままにして、内部ヘルパー メソッドを用意します。

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

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

しかし、どういうわけか、これは何らかの方法でリファクタリングする必要があるように思えます。内部は常に控えめに使用するものです。これは、すべてが何らかの形でアセンブリ内の他のすべてを使用している非常に厄介なアーキテクチャにつながる可能性があるためですが、もちろん常に例外があります。

于 2009-06-02T18:30:31.527 に答える
6

内部の明示的に実装されたインターフェイスを使用できます。

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 が定義されているアセンブリで内部アクセスを取得できます。これは、まさに必要なものです。

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

于 2011-10-11T14:09:38.027 に答える
5

C# 7.2 以降、コンストラクトprivate protected( link ) があります。フィールドからの読み取りは許可されていません (したがって、OP が意図したとおりには実行されません) が、略奪する価値があります。

于 2017-11-18T09:03:28.600 に答える
4

CLR は、保護された AND 内部 (ファミリとアセンブリのアクセシビリティと呼ばれる) の概念をサポートしており、C# はこの概念を実装/公開する必要があります。C# では、おそらく次のことを許可する必要があります。

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

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

于 2012-12-06T22:22:35.633 に答える
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);
        }
    }
}
于 2010-07-13T15:54:01.977 に答える