如何在 C# 中使属性受保护和内部?
Posted
技术标签:
【中文标题】如何在 C# 中使属性受保护和内部?【英文标题】:How to make a property protected AND internal in C#? 【发布时间】:2010-10-30 18:40:38 【问题描述】:这是我缩短的抽象类:
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 访问器受保护和内部的?
我觉得我严重滥用了访问修饰符,所以任何设计帮助都将不胜感激。
【问题讨论】:
@Noldorin:受保护的内部是受保护的或内部的。 @Mehrdad:是的,我知道。有什么意义? @Noldorin:关键是,显然,编译不是 OP 想要的...... "这个想法是,我希望能够从程序集中的任何地方调用 Report.Headers,但只允许它由派生类设置。" - 发布的代码不是这样吗?毕竟,也许我误解了它。 @Noldorin:他的意思是(据我所知)他希望只有在 两个 条件都为真时才能够访问该成员:该类是派生类并且它在同一个组件。也就是说,同一程序集中的非派生类无法访问它。 protected internal 无法实现。 【参考方案1】:这在 C# 中是不可能的。
为了完整起见,IL(家族和程序集访问修饰符)支持这一点。
【讨论】:
是否有任何构建后事件工具允许在编译后修改 IL 代码以获得所需的结果?【参考方案2】:将 getter 公开有什么问题?如果您将属性声明为
public string[] Headers get; protected set;
它满足您想要的所有条件:程序集的所有成员都可以获取该属性,并且只有派生类可以设置它。当然,程序集之外的类也可以获得该属性。那么?
如果您确实需要在程序集中但不公开地公开该属性,另一种方法是创建一个不同的属性:
protected string[] Headers get; set;
internal string[] I_Headers get return Headers;
当然,用I_
前缀装饰名字很丑。但这是一个奇怪的设计。对内部属性进行某种名称修饰是一种提醒自己(或其他开发人员)他们正在使用的属性是非正统的方式。此外,如果您后来决定像这样混合可访问性并不是解决问题的正确方法,您就会知道要修复哪些属性。
【讨论】:
只有当protected
属性的类型是public
时才有效,比如string[]
。如果 protected
属性的类型本身是 internal
- 编译失败并显示消息 Inconsistent accessibility: property type 'Library.A' is less accessible than property 'Library.OnlineStatusReport.Headers'
【参考方案3】:
我会将访问修饰符保持为受保护的状态并拥有一个内部辅助方法。
protected override string[] Headers
get return headers; // Note that get is protected
set headers = value;
internal SetHeadersInternal(string[] newHeaders)
headers = newHeaders;
但不知何故,这听起来应该以某种方式重构。内部总是我会谨慎使用的东西,因为它会导致一个非常混乱的架构,其中所有东西都以某种方式使用程序集中的其他所有东西,但当然总是有例外。
【讨论】:
【参考方案4】:您可以使用内部显式实现的接口:
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 的程序集中获得内部访问权限,这应该正是您想要的。
显式实现接口并不是一个众所周知的策略,但它解决了很多问题。
【讨论】:
【参考方案5】:从 C# 7.2 开始,构造 private protected
(link)。它不允许从现场读取(因此不完全符合 OP 的意图),但值得一试。
【讨论】:
如果与internal
结合使用,它确实可以允许读取:internal override string[] Headers get return headers; private protected set headers = value;
将是仅限内部读取和仅限内部和受保护的写入。其他组合也是可能的。【参考方案6】:
CLR 支持受保护和内部的概念(称为家族和程序集可访问性),C# 应该实现/公开这个概念。 C# 可能应该允许以下内容:
internal string[] Header get; protected set;
这样做应该 INTERSECT/AND 属性设置器的可见性修饰符,并允许您从同一程序集中的任何位置读取标题,但只能从同一程序集中的派生类中设置它。
【讨论】:
CLR 支持受保护和内部的概念(称为家族和程序集可访问性),我上面的回答表明 C# 应该实现/公开这个概念并解释建议的语法。请注意,我将 internal 修饰符放在属性上,将 protected 修饰符放在 setter 上(将“受保护的内部”放在 setter 上并不相同)。感谢您的评论,我已经编辑了我的答案以强调这个想法并避免未来的混乱。 它应该以某种方式支持......但我肯定不像它在这里......尝试建议内部和受保护的构造函数?只能从库(程序集)访问的构造函数,不应从其他库中的任何派生类型访问。也许我们可以区分“受保护的内部”和“内部受保护的”修饰符。所以第二个意味着它首先是“内部的”,然后才是“受保护的”。原始手段可用于任何派生类(“受保护”)以及内部任何地方(就像现在一样)。【参考方案7】:人们普遍认为,您不能让某些成员既受保护又成为内部成员。
确实,你不能在一行中做到这一点,包括我自己在内的许多人都希望这样做,但如果有点聪明,它是 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);
【讨论】:
内部类不必是静态的才能用于受保护的内部。我使用了你的想法,但在父类中,我有内部类的实例,用于访问我的“受保护的内部”成员。【参考方案8】:不是非常优雅但可行的解决方案,请明确实施:
internal bool _allowSetHeader = false;
protected void SetHeader(string[] newValue)
if (_allowSetHeader)
headers = newValue;
SetHeader 只能由派生类访问,除非 _allowSetHeader 设置为 true,否则它不会做任何事情,这只能由内部类完成...
【讨论】:
以上是关于如何在 C# 中使属性受保护和内部?的主要内容,如果未能解决你的问题,请参考以下文章