Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中使属性受到保护并处于内部状态?_C#_Access Modifiers - Fatal编程技术网

如何在C#中使属性受到保护并处于内部状态?

如何在C#中使属性受到保护并处于内部状态?,c#,access-modifiers,C#,Access Modifiers,这是我缩短的抽象类: abstract class Report { protected internal abstract string[] Headers { get; protected set; } } 下面是一个派生类: class OnlineStatusReport : Report { static string[] headers = new string[] { "Time", "Message" } p

这是我缩短的抽象类:

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
,但只允许由派生类设置它。我尝试将
标题设置为内部标题,但受保护的标题并不比内部标题更具限制性。有没有一种方法可以使头成为内部的,并且它的集合访问器是受保护的和内部的

我觉得我严重滥用了访问修饰符,因此非常感谢任何设计帮助。

这在C#中是不可能的


为了完整起见,IL(族和程序集访问修饰符)中支持这一点。

我会将访问修饰符保持为受保护状态,并使用一个内部助手方法

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

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

但不知何故,这闻起来似乎应该以某种方式进行重构。内部总是我会少用的东西,因为它会导致一个非常混乱的体系结构,在这个体系结构中,所有的东西都在以某种方式使用程序集中的其他所有东西,但当然总会有例外。

公开getter有什么错?如果您将财产声明为

public string[] Headers { get; protected set; }
它满足您想要的所有条件:程序集的所有成员都可以获得该属性,并且只有派生类可以设置该属性。当然,程序集之外的类也可以获取该属性。那么

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

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

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

人们普遍认为,您无法使某些成员既受保护又处于内部

诚然,你不能像很多人,包括我自己,所希望的那样,在一行中做到这一点,但有了一些聪明,它是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);
        }
    }
}

您可以使用内部显式实现的接口:

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的程序集中获得内部访问权限,这正是您想要的


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

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

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

这样做应该与属性setter的两个可见性修饰符相交/和,并允许您从同一程序集中的任何位置读取标题,但只能从同一程序集中的派生类进行设置。

因为C#7.2中存在构造
私有保护
()。它不允许从现场读取数据(因此不完全符合OP的意图),但值得获取战利品。

不完美,但却是可行的解决方案,请明确实施:

internal bool _allowSetHeader = false;

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

SetHeader只能由派生类访问,除非将“allowSetHeader”设置为true,否则它将不起任何作用,而这只能由内部类完成…

@Noldorin:protected internal是protected或internal。@Mehrdad:是的,我知道。重点是什么?@Noldorin:重点是,显然,编译精细并不是OP想要的……”想法是,我希望能够从程序集中的任何地方调用Report.header,但只允许它由派生类设置。“-发布的代码不是这样吗?说到底,也许我误解了。@Noldorin:他的意思是(据我所知),他希望只有在两个条件都满足时才能访问该成员:该类是派生类,并且位于同一程序集中。也就是说,同一程序集中的非派生类无法访问它。protected internal无法实现这一点。CLR支持protected和internal(称为族和程序集可访问性)的概念,我在上面的回答建议C#应该实现/公开这一概念,并对建议的语法进行解释。注意,我在属性上放置了内部修饰符,在setter上放置了受保护修饰符(在setter上放置“受保护的内部”时不同)。谢谢你的评论,我编辑了我的答案来强调这个观点,避免将来的混淆。它应该在某种程度上支持。。。但我肯定不是在这里。。。尝试建议内部和受保护的构造函数?构造函数,该构造函数只能从库(程序集)访问,不能从其他库中的任何派生类型访问。也许我们可以区分“内部保护”和“内部保护”修饰符。所以第二个意思是它首先是“内部的”,然后才是“受保护的”。任何派生类(“protected”)和内部任何地方(现在)都可以使用原始方法。是否有任何生成后事件工具允许在编译后修改IL代码以获得所需的结果?只有当
protected
属性的类型为
public
,如
string[]
时,它才有效。如果
受保护
属性的类型本身是
内部
,则编译失败,并显示消息
不一致的可访问性:属性类型“Library.A”比属性“Library.OnlineStatusReport.Headers”更难访问。内部类不必是静态的,就可以用于受保护的内部类。我使用了您的想法,但在父类中,我有用于访问“受保护的内部”成员的内部类的实例。如果与
internal
internal override string[]Headers{get{return Headers;}private protected set{Headers=value;}结合使用,它确实可以允许读取
将是仅内部读取和仅内部保护写入。其他组合也是可能的。