What are the advantage of assinging object fields to local variables?
I'm trying to develop some asynchronous methods for a personal project of mine, and I'm looking into the framework for reference.
I've downloaded the .NET source code to take a look at the bits and bolts more closely (with developer comments, something that Reflector doesn't give us :-P )
Anyway, in a lot of .NET classes I've came across the following pattern:
class SomeType
{
// ...
SomeClass m_Field;
// ...
SomeClass SomeMethod()
{
SomeClass localField = m_Field;
if (localField == null)
{
localField = new SomeClass();
m_Field = localField;
}
return localField;
}
}
That got me wondering what is the advantage of us开发者_StackOverflowing such pattern?
As far as I know the pattern above is worse, performance wise, than the one below:
class SomeType
{
// ...
SomeClass m_Field;
// ...
SomeClass SomeMethod()
{
if (m_Field == null)
{
m_Field = new SomeClass();
}
return m_Field;
}
}
Or am I missing something here?
In many cases the difference is purely aesthetic and subjective, but three reasons to think about one vs. the other come to mind:
Thread Safety: A lockless algorithm might need to worry about this, but if all synchronization is done through locks, it shouldn't be an issue.
Performance: It might be slightly faster in some cases, but I honestly doubt it will make a difference in most cases.
Exception Safety: Often you need to be careful to put intermediate changes into locals and then only publish the results to fields after the operations have completed without raising an exception. This acts as a transaction mechanism as nobody will see the object with only half of the fields set.
Such approach may help to protect you from situations when you call SomeMethod from one thread, but after you checked m_Field for null, control is passed to another thread, which sets it to null. Then control is returned to first thread, but it still thinks that m_Field != null, which will probably lead to NullReferenceException
As far as I remember there are couple of words about it in Richter's "CLR via C#" in chapter about events.
It may be just a hint to the compiler that the field should be read into a register rather than repeatedly accessing it in memory. There's little reason why the first version should be worse performance-wise than the second one you listed. It is pretty much the same code the compiler would generate anyway. Read the object field into a register, test if it is null, modify it as desired, then write it back to the object field in memory.
The MS .NET JIT does register allocation. For such a simple case, that temporary variable should end up being held in a register, not on the stack at all. The x86 byte code generated should then run faster than if the class member is read twice (once to check for null, once to return) for the non-null case, and faster for the null case too.
The code generator must in general write changes to fields in objects as soon as they happen, and read from an object field every time it is referenced, otherwise under some circumstances, a thread might never see changes to objects made by another thread and vice versa.
But if a local variable is used the compiler assumes it doesn't have to write changes to the local variable (or even store it in the stack) because accessing another thread's locals is not something that C# allows.
精彩评论