如何在C#中保护属性和内部?

时间:2009-06-02 18:22:49

标签: c# access-modifiers

这是我缩短的抽象类:

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只是内部的,但受保护不算比内部更严格。有没有办法使Headers内部及其set访问器受到内部保护?

我觉得我严重滥用访问修饰符,所以任何设计帮助都会非常感激。

8 个答案:

答案 0 :(得分:31)

在C#中不可能。

为了完整起见,IL(家庭和程序集访问修饰符)支持此功能。

答案 1 :(得分:16)

将吸气剂公开有什么问题?如果您将该属性声明为

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

它符合您想要的所有条件:程序集的所有成员都可以获取属性,并且只有派生类可以设置它。当然,集会外的课程也可以获得房产。所以?

如果您确实需要在程序集中公开属性但不公开,则另一种方法是创建不同的属性:

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

当然,使用I_前缀装饰名称很难看。但这是一种奇怪的设计。在内部属性上进行某种名称修改是一种提醒自己(或其他开发人员)他们正在使用的属性是非正统的方式。此外,如果您稍后决定这样的混合可访问性不是您问题的正确解决方案,那么您将知道要修复哪些属性。

答案 2 :(得分:6)

我会将访问修饰符保持为受保护并具有内部帮助方法。

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

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

但不知何故,这闻起来应该以某种方式重构。内部总是我谨慎使用的东西,因为它可能导致一个非常混乱的架构,其中一切都以某种方式使用集合中的其他东西,但当然总是例外。

答案 3 :(得分: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的程序集中获得内部访问权限,这应该是您想要的。

显式实现接口并不是一个众所周知的策略,但它解决了很多问题。

答案 4 :(得分:3)

CLR支持受保护的AND内部概念(称为系列和程序集可访问性),C#应该实现/公开这个概念。 C#应该允许以下内容:

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

这样做应该INTERSECT / AND属性设置器的两个可见性修饰符,并允许您从同一个程序集中的任何位置读取Headers,但只能从同一程序集中的派生类设置它。

答案 5 :(得分: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);
        }
    }
}

答案 6 :(得分:2)

从C#7.2开始,有private protectedlink)。它不允许从场上读取(因此不能完全符合OP的意图),但值得掠夺。

答案 7 :(得分:0)

不是完美的解决方案,而是可行的解决方案,请明确实现:

internal bool _allowSetHeader = false;

protected void SetHeader(string[] newValue)
{
   if (_allowSetHeader)
   {
     headers = newValue;
   }
}

SetHeader只能由派生类访问,除非_allowSetHeader设置为true(只能由内部类完成),否则它将什么都不做。