[英]Difference between readonly keyword/Expression-bodied members in c#?, which is better?
In c# readonly members can be reduced to readonly auto properties/expression-bodied members for immutable members is expression-bodied members are better then using readonly keywords? 在c#中,readonly成员可以简化为只读自动属性/表达式成员,对于不可变成员,表达式成员比使用readonly关键字更好吗?
Using readonly keywork: 使用readonly keywork:
public static readonly string COMPANY_NAME= "XYZ";
Using Expression-bodied Members: 使用表达身体的成员:
public static string COMPANY_NAME => "XYZ";
I have come across various forums and solution that suggest expression bodied members for short hand use, and i could not find how it differs in performance. 我遇到过各种论坛和解决方案,建议表达身体的成员用于短手使用,我无法找到它在性能上的差异。
Let's dive deep and see what compiler does for different types of fields. 让我们深入了解一下编译器对不同类型的字段所做的工作。
class Program
{
public const string ConstString = "mesa const";
public static readonly string ReadonlyStatic = "mesa readonly";
public static string ExpressionBodied => "mesa expression";
public static string GetInitialized {get;} = "mesa get";
public static string GetWithBody { get { return "mesa get"; } }
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
System.Console.WriteLine("readonly:" + ReadonlyStatic);
System.Console.WriteLine("const:" + ConstString);
System.Console.WriteLine("expression bodied:" + ExpressionBodied);
System.Console.WriteLine("get initialized:" + GetInitialized);
System.Console.WriteLine("get with body:" + GetWithBody);
}
}
const string
creates a literal string
and will be evaluated at call site: const string
创建一个literal string
,将在调用站点进行评估:
.field public static literal string ConstString = "mesa const"
// call site:
IL_0021: ldstr "const:mesa const"
IL_0026: call void [System.Console]System.Console::WriteLine(string)
static readonly
creates a field that is initialized in ctor and means only one field reference when used: static readonly
创建一个在ctor中初始化的字段,并且在使用时仅表示一个字段引用:
.field public static initonly string ReadonlyStatic
// call site:
IL_000c: ldstr "readonly:"
IL_0011: ldsfld string readonly_props.Program::ReadonlyStatic
IL_0016: call string [System.Runtime]System.String::Concat(string, string)
IL_001b: call void [System.Console]System.Console::WriteLine(string)
Expression bodied member generates a getter, which returns constant value: Expression bodied成员生成一个getter,它返回常量值:
.method public hidebysig static specialname string
get_ExpressionBodied() cil managed
{
.maxstack 8
// [9 50 - 9 67]
IL_0000: ldstr "mesa expression"
IL_0005: ret
} // end of method Program::get_ExpressionBodied
// call site:
IL_002c: ldstr "expression bodied:"
IL_0031: call string readonly_props.Program::get_ExpressionBodied()
IL_0036: call string [System.Runtime]System.String::Concat(string, string)
IL_003b: call void [System.Console]System.Console::WriteLine(string)
Readonly property with initialization generates an additional backing field for the initializing value. 初始化的只读属性会为初始化值生成一个额外的支持字段。
.field private static initonly string '<GetInitialized>k__BackingField'
.method public hidebysig static specialname string
get_GetInitialized() cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 8
// [10 46 - 10 50]
IL_0000: ldsfld string readonly_props.Program::'<GetInitialized>k__BackingField'
IL_0005: ret
} // end of method Program::get_GetInitialized
// call site:
IL_0041: ldstr "get initialized:"
IL_0046: call string readonly_props.Program::get_GetInitialized()
IL_004b: call string [System.Runtime]System.String::Concat(string, string)
IL_0050: call void [System.Console]System.Console::WriteLine(string)
A Property getter with full body is a bit longer: 具有全身的属性获取器有点长:
.method public hidebysig static specialname string
get_GetWithBody() cil managed
{
.maxstack 1
.locals init (
[0] string V_0
)
// [11 48 - 11 49]
IL_0000: nop
// [11 50 - 11 68]
IL_0001: ldstr "mesa get"
IL_0006: stloc.0 // V_0
IL_0007: br.s IL_0009
// [11 69 - 11 70]
IL_0009: ldloc.0 // V_0
IL_000a: ret
} // end of method Program::get_GetWithBody
// call site:
IL_0056: ldstr "get with body:"
IL_005b: call string readonly_props.Program::get_GetWithBody()
IL_0060: call string [System.Runtime]System.String::Concat(string, string)
IL_0065: call void [System.Console]System.Console::WriteLine(string)
From that, we can order them by amount of code (and calls) they generate: 从那以后,我们可以通过他们生成的代码(和调用)来订购它们:
const string
is definitely the fastest one, but can cause unexpected behavior in case of change, when used from other assembiles (as other answers mentioned) const string
绝对是最快的,但是在更改的情况下可能会导致意外行为,当从其他集合中使用时(如提到的其他答案) static readonly
comes right behind, with one field access static readonly
后面,一个字段访问 static string ExpressionBodied => "xxx"
will cause a method call (getter) that simply returns a constant static string ExpressionBodied => "xxx"
将导致只返回常量的方法调用(getter) static string GetInitialized {get;} = "xxx"
will result in a method call and a field access static string GetInitialized {get;} = "xxx"
将导致方法调用和字段访问 static string GetWithBody { get { return "xxx"; } }
static string GetWithBody { get { return "xxx"; } }
will cause a method call that returns a constant, but wih additional memory allocation, it would seem static string GetWithBody { get { return "xxx"; } }
会导致一个返回常量的方法调用,但是看起来还有额外的内存分配 In practice, the performance differences will probably be unobservable. 在实践中,性能差异可能是不可观察的。 As pointed out, IL code can be further optimized by JIT, so you can end up with effectively the same performance.
正如所指出的,IL代码可以通过JIT进一步优化,因此您可以最终获得相同的性能。 Nevertheless, I prefer to go with option 1. or 2.
不过,我更喜欢选择1.或2。
First, you should use const
with string
constants, not readonly
. 首先,你应该使用
const
与string
常量,而不是readonly
。 You should use the latter only for objects requiring a constructor call to construct them. 您应该仅将后者用于需要构造函数调用来构造它们的对象。
There is a side note to this though, as stated in comments, you should be aware that constants will be optimized even across assemblies (so your library constants can also be evaluated as constants on compile time by the referenced library). 这里有一个注意事项,正如注释中所述,你应该知道常量甚至会跨程序集进行优化(因此你的库常量也可以在引用库的编译时被评估为常量)。 That would mean that with minor version updates, you could end up with another constant value in the assembly than in your library.
这意味着,通过次要版本更新,您可能最终在程序集中使用另一个常量值,而不是在库中。 In such cases you should keep using
static readonly
. 在这种情况下,您应该继续使用
static readonly
。
Second, there is a huge difference between static readonly
fields and static
properties. 其次,
static readonly
字段和static
属性之间存在巨大差异。 The static
properties will get evaluated each and every time you call it. 每次调用
static
属性时都会对其进行评估。 The static readonly
is slightly optimized, since it does only do a single assignment. static readonly
稍微优化,因为它只进行一次分配。
In this case, the overall results will appear the same, but realise that they are quite different. 在这种情况下,整体结果将显得相同,但意识到它们是完全不同的。
The first defines a readonly
field. 第一个定义了一个
readonly
字段。 The initialization expression to the right of the =
runs once, and the field always returns that value. =
右边的初始化表达式运行一次,字段始终返回该值。
The second defines a get
-only property. 第二个定义了一个
get
-only属性。 The expression to the right of the =>
will be evaluated each time it is accessed. 每次访问时 ,都会评估
=>
右侧的表达式。
In this case, your expressions are deterministic and produce immutable objects. 在这种情况下,表达式是确定性的并生成不可变对象。 If neither of these were true, then the difference between them would be observable (by the second returning different results or by being able to modify the contents of the first)
如果这些都不是真的,那么它们之间的差异将是可观察的(通过第二次返回不同的结果或者能够修改第一个的内容)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.