C# 私有、静态和只读

24

我正在审查一些log4net的代码,然后看到了这段。

private static readonly ILog logger = LogManager.GetLogger(typeof(AdminClient));

我想知道为什么需要使用private static readonly。

据我的理解,private意味着变量在类之外不能使用,除非有访问器方法或获取属性。

static意味着变量的作用域仅限于此文件。

readonly意味着只能读取值,不能赋值。

因此,我认为编写此代码的人将其声明为private,因为他们不希望它在类之外使用,并且将其设置为static,以便不希望它在文件之外使用。但是,如果有一个获取属性,static会防止这种情况发生吗?

我认为我可以理解readonly,并且只能从中读取值而不能设置。

非常感谢任何建议,


关于这个特定模式的一个有趣的侧面:我曾经将其声明为 protected static readonly,这让我从 VS Code Analysis 得到了一个 "CA2104: Do not declare read only mutable reference types" 的警告。如此处所提到的,“protected readonly 字段并不是那么清晰。由于 protected,您可能希望派生类可以初始化该字段。”将声明更改为 private static readonly 即可解决此问题。 - CrazyPyro
9个回答

49
  • private 该logger字段只能在类内部使用(即使是子类也不行),如果你不设置为私有,其他类可能会使用你的logger来记录自己的日志信息而误导读者。
  • static 这个属性被附加到了类上,因此它不会随着类的每个实例而重复。如果你不设置为静态属性,那么每次系统创建对象时,logger属性都会占用额外的内存空间。(你对这点的理解有误。)
  • readonly logger字段不应该被修改。

10

我认为你对静态变量的理解有误。静态并不意味着“不能在文件外使用”。静态的含义是:每个类中只有一个。这个声明所做的是创建一个仅分配一次(静态),仅在类中可用(派生类中也不可用)(private),且不能在初始化之后写入(readonly)的记录器。

不过,问得好!


6

static并不意味着它不能从其他文件访问 - 这不是C语言。static关键字意味着logger对象是一个类变量而不是实例变量,因此即使从该类的不同对象中访问,它们都将引用相同的logger对象。


2

C#中的static表示成员与类相关,而不是与类的实例相关。readonly很重要,因为在C#中大多数变量(特别是这个变量)都是引用变量。readonly意味着这个变量将始终引用相同的记录器。


2

开发人员所说的是,当他们在该类的任何实例中调用logger.Info(...)时,他们想要使用一个共同的(静态)实例(因此不需要为每个类实例创建新的记录器),他们想要确保自从创建以来它没有改变(只读),如果我们在派生类中的虚函数中,则希望确保不要错误地使用基类的记录器(私有)。


1
将一个只读标志放在私有变量上的原因是声明该变量将始终引用相同的对象。 虽然将其设为私有可使其对类外部的任何人都不可见,但这样我们可以确保没有意外地使用类似以下方式来重写变量:
logger = LogManager.GetLogger(typeof(AdminClient));

在我们的类中的其他地方。使用readonly,它就无法编译(除非它在之前没有被初始化,并且我们在(静态)构造函数中)


1

静态变量属于“类变量”类别,类变量是与类相关联而不是与类对象相关联的变量,另一方面,实例变量是与类对象相关联的变量,这意味着每次初始化类对象时,该对象将拥有其自己的那个“实例变量”(非静态),而静态变量在运行程序中共享于所有类对象,例如链表的大小等。 readonly是C#关键字,用于使变量只读,Java没有提供这样的功能,您必须编写一个公共方法来访问您不想被篡改的变量。


1

readonly变量与const非常相似,因为其值在其生命周期内是恒定不变的。区别在于,readonly变量在运行时初始化,而const在编译时初始化。Static在某种程度上意味着变量的实例不依赖于声明它的对象的实例。它的生命周期从函数调用到函数调用持续存在。静态变量访问速度更快,因为其存储在整个程序的持续时间内保持分配状态。因此,了解这一点,我们可以回到您的问题。

为什么'logger'是静态成员?这是一个设计决策。我需要知道您如何使用它来回答这个问题。为什么它是只读的?因为它似乎只被初始化一次并且在整个实例中都被使用。我们可以通过在初始化后将其设置为“只读”来确保没有其他人会篡改logger的值。


0

抱歉,我知道这个问题已经有答案了,而且很老了,但是我想让任何看到这篇文章的人都知道这就是如何设置“Singleton”模式的方法。任何想要了解问题中代码示例更多信息的人都可能从学习更多关于单例模式以及它们的用途(中介、记录器、异步回调等)中受益。

// 关于单例模式的母舰内容
http://msdn.microsoft.com/en-us/library/ff650316.aspx
http://msdn.microsoft.com/en-us/library/ff650849.aspx

// 一个关于它们的很棒的SO讨论
What is so bad about singletons?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接