views:

89

answers:

4

In C# (or VB .NET), does the compiler make attempts to optimize property accesses? For eg.,


public ViewClass View
{
    get
    {
        ...
        Something is computed here
        ....
    }
}

if (View != null)
    View.Something = SomethingElse;


I would imagine that if the compiler could somehow detect that View remains constant between the two accesses, it can refrain from computing the value twice. Are these kind of optimizations performed?

I understand that if View has some intensive computations, it should probably be refactored into a function (GetView()). In my particular case, View involves climbing the visual tree looking for an element of a particular type.

Related: Any references on the workings of the (Microsoft) C# compiler?

+1  A: 

No, which is why you should use Lazy<T> to implement a JIT calculation.

Steven Sudit
A: 

From my understanding there is no implicit caching - you have to cache the value of a given property yourself the first time it is calculated

For example:

  object mCachedValue = null;
    public Object MyProperty
    {
        get
        {

            if (mCachedValue == null)
            {
               lock(mCachedValue)
                {
                   //after acquiring the lock check if the property has not been initialized in the mean time - only calculate once
                    if (mCachedValue == null)
                    {
                        //calculate value the first time 
                    }
                }
            }
            return mCachedValue;
        }
Ando
The idea is right, but this code is not. It lacks thread safety, which is why I recommended using `Lazy<T>` instead.
Steven Sudit
You are right, I did not consider multithreading. I modified the code to take thread safety into account.
Ando
Hate to disappoint you, but that's not guaranteed to work, either. Just use `Lazy<T>`. Don't take my word for it: http://csharpindepth.com/Articles/General/Singleton.aspx
Steven Sudit
+5  A: 

Not in general, no. As Steven mentioned there are numerous factors to consider regarding multithreading, if you truly are computing something that might change, you're correct it should be refactored away from a property. If it won't change, you should lazy-load it (check if the private member is null, if so then calculate, then return the value).

If it won't change and depends on a parameter, you can use a Dictionary or Hashtable as a cache - given the parameter (key) you will store the value. You could have each entry as a WeakReference to the value too, so when the value isn't referenced anywhere and garbage collection happens, the memory will be freed.

Hope that helps.

Kieren Johnstone
Thanks for bringing up some of the other factors.
Steven Sudit
+2  A: 

The question is very unclear, it isn't obvious to me how the getter and the snippet below it are related. But yes, property accessors are normally heavily optimized. Not by the C# compiler, by the JIT compiler. For one, they are often inlined so you don't pay for the cost of a method call.

That will only happen if the getter doesn't contain too much code and doesn't monkey with locks and exception handling. You can help the JIT compiler to optimize the common case with code like this:

get
{
    if (_something == null) {
        _something = createSomething();
    }
    return _something;
}

This will inline the common case and allow the creation method to remain un-inlined. This gets typically compiled to three machine code instructions in the Release build (load + test + jump), about a nano-second of execution time. It is a micro-optimization, seeing an actual perf improvement would be quite rare.

Do note that the given sample code is not thread-safe. Always write correct code rather than fast code first.

Hans Passant
Hans, can you confirm whether the caller has to be in the same assembly in order for the property to be inlined?
Steven Sudit
@Steven, I can confirm it does *not* have to be in the same assembly. That would wreck inlining .NET framework properties.
Hans Passant
Good to know. Would you be able to post a reference link?
Steven Sudit
@Steven, it is easy to confirm by looking at the (optimized!) machine code. If you don't know how to do that then you could ask an SO question about it.
Hans Passant
I'm asking because it has come up before on SO, but with some ambiguity in the results, so I'd like to go back and add any definitive references to settle the matter. Thanks, anyhow.
Steven Sudit