如何在 C# 中使属性受保护且为内部属性?

发布于 2024-07-22 16:35:33 字数 713 浏览 11 评论 0原文

这是我缩短的抽象类:

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 并不比内部更具限制性。 有没有办法使标头成为内部及其设置访问器受保护和内部?

我觉得我严重滥用了访问修饰符,因此任何设计帮助将不胜感激。

Here is my shortened abstract class:

abstract class Report {

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

Here is a derived class:

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

The idea is, I want to be able to call Report.Headers from anywhere in the assembly, but only allow it to be set by derived classes. I tried making Headers just internal, but protected does not count as more restrictive than internal. Is there a way to make Headers internal and its set accessor protected AND internal?

I feel like I'm grossly misusing access modifiers, so any design help would be greatly appreciate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

李不 2024-07-29 16:35:33

这在 C# 中是不可能的。

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

It's not possible in C#.

Just for the sake of completeness, this is supported in IL (family and assembly access modifier).

魔法少女 2024-07-29 16:35:33

将 getter 公开有什么问题吗? 如果您声明该属性,因为

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

它满足您想要的所有条件:程序集的所有成员都可以获取该属性,并且只有派生类可以设置它。 当然,程序集外部的类也可以获得该属性。 所以?

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

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

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

What's wrong with making the getter public? If you declare the property as

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

it meets all of the criteria you want: all members of the assembly can get the property, and only derived classes can set it. Sure, classes outside the assembly can get the property too. So?

If you genuinely need to expose the property within your assembly but not publicly, another way to do it is to create a different property:

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

Sure, it's ugly decorating the name with that I_ prefix. But it's kind of a weird design. Doing some kind of name mangling on the internal property is a way of reminding yourself (or other developers) that the property they're using is unorthodox. Also, if you later decide that mixing accessibility like this is not really the right solution to your problem, you'll know which properties to fix.

热血少△年 2024-07-29 16:35:33

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

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

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

但不知怎的,这听起来像是应该以某种方式重构。 内部始终是我很少使用的东西,因为它可能会导致非常混乱的体系结构,其中所有内容都以某种方式使用程序集中的其他所有内容,但当然总有例外。

I would keep the access modifier as protected and have an internal helper method.

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

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

But somehow, this smells like it should be refactored somehow. Internal is always something I'd use sparingly because it can lead to a very messy architecture where everything is somehow using everything else within the assembly, but of course there's always exceptions.

来日方长 2024-07-29 16:35:33

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

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

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

You could use an internal explicit implemented Interface:

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

Now you get internal access in the assembly where IReport is defined, which should be exactly what you want.

Implementing interfaces explicitly isn't a well known strategy, but it solves alot of problems.

慵挽 2024-07-29 16:35:33

从 C# 7.2 开始,有构造 private protected (链接)。 它不允许从现场读取(因此并不完全符合OP的意图),但值得抢夺。

Since C# 7.2 there is construct private protected (link). It does not allow reading from the field (thus does not do exactly what the OP intends), but worth taking a loot.

长不大的小祸害 2024-07-29 16:35:33

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

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

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

The CLR supports the concept of protected AND internal (known as family-and-assembly accessibility) and C# SHOULD implemented/expose this concept. C# should probably allow the following:

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

Doing so should INTERSECT/AND both visibility modifiers for the property setter and allow you to read Headers from anywhere within the same assembly but only set it from derived classes within the same assembly.

故事和酒 2024-07-29 16:35:33

人们普遍认为,您不能让某些成员既受到保护又处于内部。

确实,你不能像包括我自己在内的许多人所希望的那样,用一行代码来做到这一点,但只要有一些聪明才智,它是 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);
        }
    }
}

It's a common belief that you cannot make some members both protected AND internal.

And its true that you cannot do so in a single line, as many, including myself, would wish, but with some cleverness it is 100% do-able.

//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);
        }
    }
}
一绘本一梦想 2024-07-29 16:35:33

不是完美的优雅,但一个可行的解决方案,明确地实现它:

internal bool _allowSetHeader = false;

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

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

Not perfectly elegant but a workable solution, implement it explicitly :

internal bool _allowSetHeader = false;

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

SetHeader can only be accessed by a derived class and it will do nothing unless _allowSetHeader is set true which can only be done by an internal class...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文