当前位置:  开发笔记 > 编程语言 > 正文

静态只读与const

如何解决《静态只读与const》经验,为你挑选了11个好方法。

我已经阅读了各地conststatic readonly各个领域.我们有一些只包含常量值的类.用于我们系统中的各种事物.所以我想知道我的观察结果是否正确:

这些常量值是否应始终static readonly适用于所有公开的内容?并且仅const用于内部/受保护/私有值?

您有什么推荐的吗?我是否可能甚至不使用static readonly字段,而是使用属性?



1> Marc Gravell..:

public static readonly田地有点不寻常; public static属性(只有a get)会更常见(可能由private static readonly字段支持).

const值直接烧入呼叫站点; 这是双刃:

如果在运行时获取值,可能是从config获取它是没用的

如果更改const的值,则需要重建所有客户端

但它可以更快,因为它避免了方法调用...

......无论如何,JIT有时可能已将其内联

如果值永远不会改变,那么const就可以了 - Zero等等做出合理的反应; p除此之外,static属性更常见.


@Michael - 和往常一样的理由; 它隐藏了实施.您可能会发现(稍后)您需要延迟加载,基于配置,外观或其他任何内容.实际上,要么通常都很好......
根据定义@CoffeeAddict,常量**不是**从配置文件中提取值; 它在编译时作为文字刻录.在运行时*可以使用常量*的唯一方法是通过对字段的反射.在您尝试使用它的任何其他时间,编译器**已经**替换*常量*用于*literal*用法; 即,如果代码中的方法使用6个常量,并将其检查为IL,则不会提及任何常量查找; 文字值将简单地加载到原位
@MarcGravell - 注意:`readonly`字段不能用在switch/case语句中,而是需要它们是`const`.
为什么房地产?如果它是一个不可变的类,我认为没有区别.
@didibus实际上,将字段更改为属性会破坏API.C#中的字段有效地充当变量,而C#中的属性是用于编写getter方法和/或setter方法的语法助手.当涉及其他组件时,这种差异很重要.如果将字段更改为属性,并且其他程序集依赖于此字段,则必须重新编译其他程序集.
@Luciano:我看到你现在的意思,你可以打开只读变量,但你不能使用readonly变量.这是有道理的,但起初有点不清楚.
@TalalYousif所有`public`字段都有点不寻常; 大多数领域都是"私人" - 并且有充分的理由.`const`经常是`public`,当然,但那是不同的.如果你经常暴露`public`字段,我认为这是一个错误
@Mark:对于常量,我没有看到使用像这样的属性"public static int NumberOfWheels {get {return 4;}}"实际上比使用像"static readonly int NumberOfWheels = 4;"这样的公共字段更常见.您能否详细说明您的想法,或者可能会展示一个示例,说明您在本案例中会更常见到的内容?
@MarcGravell为什么Public static readonly字段有点不寻常?

2> Michael Stum..:

static readonly如果Consumer在不同的程序集中,我会使用.拥有const消费者在两个不同的组件是一个很好的方式射击自己的脚.


所以我认为,正如一些人已经提到或暗示的那样,如果将公用事物公开,那么对于实际众所周知的常量值,只使用const可能是明智的,否则它们应该保留给内部,受保护或私有访问范围.
@Iiridayn是的,这不是一个糟糕的方式来看待它.有一些边缘情况需要考虑(例如,如果使用Reflection,或者如果属性需要值),并且有"public const"的有效用途(例如,标准的任何部分.无论何时我使用XML,有一个带有一堆`public const string`的命名空间文件.)但一般来说,只有在正确考虑其含义后才能使用`public const`.

3> Peter..:

几点需要注意的相关事项:

const int a

必须初始化.

初始化必须在编译时.

readonly int a

可以使用默认值,而无需初始化.

初始化可以在运行时完成(编辑:仅在构造函数内).


仅在`ctor`内.

4> Jeppe Stig N..:

这只是对其他答案的补充.我不会重复它们(现在四年后).

在某些情况下,a const和非const具有不同的语义.例如:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

打印出来True,而:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

写道False.

原因是该方法x.Equals有两个重载,一个接受a short(System.Int16),另一个接受a object(System.Object).现在问题是一个或两个是否适用于我的y论点.

y是一个编译时间常数(字面),所述const情况下,也有不存在的隐式转换变得重要 int short提供的int是一个常数,并且条件是C#编译器验证其值的范围内short(这42是).请参阅C#语言规范中的隐式常量表达式转换.所以必须考虑两个重载.过载Equals(short)是优选的(任何short是一个object,但不是全部objectshort).因此y转换为short,并使用该重载.然后Equals比较两个short相同的值,并给出true.

y不是一个常数,不隐含从转换intshort存在.那是因为一般情况下int可能太大而无法适应short.(显式转换确实存在,但我没有说Equals((short)y),所以这不相关.)我们看到只有一个重载适用,Equals(object)一个.所以y是盒装到object.然后Equals将比较a System.Int16和a System.Int32,并且因为运行时类型甚至不同意,所以会产生false.

我们得出结论,在某些(罕见)情况下,将const类型成员更改为static readonly字段(或者在可能的情况下,将其更改为方式)可以更改程序的行为.


对接受的答案的一个很好的补充.我想补充一点,数据类型和其他类似指南(如try catch等)的正确转换应该是有经验的程序员的主要内容,而不是留给编译器.不过,我从这里学到了一些新东西.谢谢.

5> Chris S..:

需要注意的一点是const仅限于原始/值类型(异常是字符串)


实际上`const`也可以用于其他类型,除了它必须被初始化为null,这使得它无用:)
在`System.Exception`中的异常?:)
@nawfal更确切地说,唯一可以使用`const`的**值类型**是`sbyte`,`byte`,`short`,`ushort`,`int`,`uint`,`long` ,`ulong`,`char`,`float`,`double`,`decimal`,`bool`,以及任何`enum`类型.`const`不能用于其他值类型,如`DateTime`或`TimeSpan`或`BigInteger`.它也不能用于`IntPtr`结构(被某些人认为是"原始"类型;术语原始类型在C#中令人困惑).↵↵`const`可用于所有**引用类型**.如果类型是`string`,则可以指定任何字符串值.否则,该值必须为"null".

6> Yeasin Abedi..:

静态只读:可以static在运行时通过构造函数更改值.但不是通过成员函数.

常量:默认情况下static.无法从任何地方更改值(Ctor,Function,runtime等no-where).

只读:可以在运行时通过构造函数更改值.但不是通过成员函数.

你可以看一下我的repo:C#属性类型.


@FerR你去:https://github.com/yeasin90/advanced-csharp/blob/master/CSharpAdvanced/VariableTypes.cs

7> yazanpro..:

所述readonly关键字是从不同的const关键字.一个const字段只能在外地的声明进行初始化.一个readonly字段可以在声明或构造函数初始化.因此,readonly根据使用的构造函数,字段可以具有不同的值.此外,虽然const字段是编译时常量,但该readonly字段可用于运行时常量

这里简短而明确的MSDN参考



8> Ramesh Rajen..:

const并且readonly是相似的,但它们并不完全相同.

const字段是一个编译时间常数,这意味着该值可以在编译时计算.甲readonly字段允许在其中一些代码必须结构的类型的期间运行附加情景.施工后,readonly不能改变油田.

例如,const成员可用于定义以下成员:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

因为像3.14和0这样的值是编译时常量.但是,请考虑您定义类型并希望提供一些预制实例的情况.例如,您可能希望定义一个Color类并为常用颜色(如Black,White等)提供"常量".使用const成员不可能这样做,因为右侧不是编译时常量.可以使用常规静态成员执行此操作:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

但是,通过交换黑白值,没有什么能阻止Color的客户端使用它.不用说,这会导致Color类的其他客户端惊慌失措."只读"功能解决了这种情况.

通过readonly在声明中简单地引入关键字,我们保留了灵活的初始化,同时防止客户端代码混乱.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

有趣的是,const成员总是静态的,而readonly成员可以是静态的,也可以不是静态的,就像常规字段一样.

可以将单个关键字用于这两个目的,但这会导致版本控制问题或性能问题.假设我们为此(const)使用了一个关键字,开发人员写道:

public class A
{
    public static const C = 0;
}

而另一个开发人员编写的代码依赖于A:

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

现在,生成的代码能否依赖于AC是编译时常量的事实?即,AC的使用是否可以简单地用值0代替?如果你对此说"是",那么这意味着A的开发人员无法改变AC初始化的方式 - 这在未经许可的情况下将A的开发人员联系在一起.

如果你对这个问题说"不",那么就会错过重要的优化.也许A的作者肯定AC会永远为零.const和readonly的使用允许A的开发者指定意图.这样可以获得更好的版本控制行为以及更好的性能.



9> Peter Meyer..:

我倾向于尽可能使用const,如上所述,它仅限于文字表达式或不需要评估的东西.

如果我对这个限制感到热烈,那么我只需要一个警告即可回退到静态读取状态.我通常会使用带有getter和后备私有静态只读字段的公共静态属性,如Marc 在这里提到的那样.


为什么const是你的首选?仅仅因为表现?

10> mayank..:

Const: Const只不过是"常量",这是一个变量,其值在编译时是常量.并且必须为其分配值.默认情况下,const是静态的,我们不能在整个程序中更改const变量的值.

Static ReadOnly:静态Readonly类型变量的值可以在运行时分配,也可以在编译时分配,并在运行时更改.但是这个变量的值只能在静态构造函数中更改.而且无法进一步改变.它只能在运行时更改一次

参考:c-sharpcorner



11> 小智..:

当向其他程序集公开可能在更高版本中更改的值时,静态只读字段是有利的.

例如,假设程序集X公开一个常量,如下所示:

public const decimal ProgramVersion = 2.3;

如果程序集Y引用X并使用此常量,则值2.3将Y在编译时被烘焙到程序集中.这意味着如果X稍后使用常量设置为2.4重新编译,Y仍将使用旧的值2.3直到Y重新编译.静态只读字段可以避免此问题.

另一种看待这种情况的方法是,根据定义,未来可能发生变化的任何值都不是恒定的,因此不应该表示为一个.

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有