Motivation

The only problem is that the condition should work separately for every call of the predicate of the “if” block; ideally, it must be sensitive to the location of the code line.

I would probably agree in advance with those saying that such usage would be a sign of some design flaw. There is one “but”, though: this is not always your fault; very often you are dealing with someone else’s code. Typically, you have to supply an event handler, but the point where the event is raised and conditions for the event are often beyond your control.

I mostly face similar situations in using UI libraries. For example, if you’re really careful about focusing of the controls, Z-order, etc., and if the initialization of the window is more complicated, you know that certain adjustments are only possible when a window is shown on screen, activated or receives keyboard focus for the very first time during application life time. In practice, dealing with a concrete event handler will look something like this:

This is as trivial as shown in this example; yet, this is a common and familiar annoyance. First, the code is not local: you need to add the Boolean (or bit-mapped enumeration) slot to the set of the class instance variables every time you need once-in-a-lifetime behavior — for the sole purpose of using it in the code practically identical to the one in the sample below. Secondly, you should not mess up the sign of the predicate and Boolean value in three places in the code. Finally, you will better rename the variable when you decide to move the behavior from one event handler to another. This is quite enough to cause unpleasant déjà vu feeling even though this repetitive boring work is done in reality.

Solution: Stack Trace Comes to Help

The universal solution is based on System.Diagnostics.StackTrace. To start with, this is how the usage looks like:

if (FirstTime.Here)
ThisWillHappenButOnlyOnce();

Whenever the static property “FirstTime.Here” is read, it returns “true” if called for the very first time during the application life time and “false” otherwise. This holds for every distinct code location: the same code placed anywhere else in the code will return “true” again, but only once — even if this location is in the same method body. It also holds regardless of the build configuration; it does not depend on the availability of the debug information.

As this code fragment depends on few other declarations, I'll explain what they mean (please look at the full source code for details).

First of all, we need to uniquely identify code locations where the “Here” method is called. Looking at the stack frame data shows that such identification can be based on the combination of the calling method’s handle and the “native offset” of the method call within its nesting method body. Secondly, these two values are combined in the structure “CodeLocationKey”. As this structure is used as a dictionary key, its identity rules are built accordingly using the usual technique based on overridden “object.Equals” and “object.GetHashCode” methods. In this way, two instances of “CodeLocationKey” are considered as equal if both methods' handle and offset are equal. The static dictionary “CodeLocationDictionary” is defined as “System.Collections.Generic.Dictionary<CodeLocationKey>”. Why 64-bit unsigned integer is used for dictionary values, while simple Boolean could do the trick? I'll explain this in the next section.

For thread safety, “ReaderWriterLockSlim” is used in upgradeable mode. There is a particular reason to do so: the same location of the code calling “Here” causes accessing the dictionary for reading during every call, but write access will be required only for the very first time. In this way, multiple threads can get read-only access to the dictionary most of the time, when they get the lock in upgradeable read mode and no thread gets it in write mode.

The code in the loop also shows how to find the right stack frame to be used for identification of the calling method, based on the type of “FirstTime” class. Note that the calculation of the type does not depend on the coded type name, neither is it repeated during the life time of the application; instead, this is optimized based on lazy evaluation.

What to do with the Instances?

The solution presented above is quite good for static code or for use in the object instances unique in the application, such as main application form or any kind of singleton. What can be done if the once-in-a-lifetime behavior is needed per object instance, be it an instance representing one of the many child windows, controls, menu items and the like?

My original solution was a separate static class which would calculate the dictionary key of different type, with an additional field representing the user's instance. After reading the first version of this article, Paulo Zemek pointed out that this would prevent the instance from being collected by the Garbage Collector. Thank to his note, I immediately saw it could potentially cause a memory leak. For example, if the application creates statically unknown number of instances of, say, a control representing text document, every time a document is deleted and new document is created the memory allocated by the instance of the old document will not be reclaimed, because it is held by a static dictionary whose life time is about the life time of the whole process. In this way, repeated deleting and creating new documents would claim more and more memory. Even though this problem could be resolved, the whole idea of keeping extra data in the dictionary key does not provide enough flexibility. The user might also want to use the “FirstTime.Here” predicate per thread, per combination of thread and instance, or anything else.

Instead, all needs for this functionality can be covered by having a non-static version of the class “FirstTime”. For this purpose, I've added a new non-static nested class “FirstTime.Instance” to the “FirstTime”; this new class has to be nested in “FirstTime” to allow code reuse between the two:

For each instance of the “FirstTime.Instance” class, the counting of the calls to the property “Here” will be performed separately, using the separate instances of the dictionary. In case of multi-threading access to dictionaries, two or more threads will be inter-locked only while accessing the same instance of the dictionary.

What if You Want to Know More?

I made the solution above as slick as I could. However, there is some redundancy in storing of the 64-bit value unsigned integer in the dictionary key. This value represents the number of calls to the “Here” property. I assume this information could help for debug and diagnostic purposes.

Instead of exposing the number of calls through one universal class, I created a separate class with the same name and compatible interface under different name space. Original “FirstTime” comes under name space “SA.Univeral.Utilities” while the diagnostic version of it comes under name space “SA.Univeral.Utilities. Diagnostics”, so one could finish the debugging and then switch to more economic non-diagnostic version and squeeze an extra bit of performance.

How the diagnostic version can possibly have compatible interface and yet expose the additional information on number of calls? The trick is that the types of “Here” are different, yet one-way assignment-compatible: “SA.Univeral.Utilities.Diagnostics.FirstTime.Here” can be used whenever “SA.Univeral.Utilities.FirstTime.Here” is used, but not visa versa.

The assignment compatibility between the two return types of “Here” is based on implicit operator declarations. For diagnostic version, the type “CodeLocationData” is used instead of Boolean:

Beyond this, the difference between basic and diagnostic versions of “FirstTime” class is trivial; please find more details in the full source code.

My motivation for the use of 64-bit unsigned value for the call count looks funny enough to explain it here.

Imagine all of your code is only busy with calling “FirstTime.Here”, and also imagine you have such fantastic CPU speed that each whole cycle takes only 1 µsec. If you used 32-bit unsigned integer for your call counter, it would overflow in just 1.19 hours. For 64-bit, this would take almost… 584 thousand years.

I really hope even if your code lives long enough and computers get way faster, you hardly will face a deadline much closer than just a half million of your development years. This time should be enough to port your code to, say, 128 bit.

Solution Cost

On my system a call to “FirstTime.Here” takes about 40 µsec, with thread locking contributing less than 2% of this time. Is this fast enough?

If the technique is rightfully used for UI purposes, only one or just few calls to “Here” can happen per single click of the mouse of keyboard event. In such situations, even a millisecond or few would not count.

As to the memory consumption, there can be no more than two dictionaries per Application Domain (if both regular and diagnostics versions of “FirstTime” class are used at the same time), and the number of keys cannot exceed total number of code lines where a call to “Here” or “VisitNumber” is written; with each key taking 16 bytes. For the non-static class “FirstTime.Instance”, there will be a separate dictionary per instance.

Building Code and Samples

The code is designed to support Microsoft.NET v.2 and above.

I developed two UI samples, one for Windows Forms, another one — targeted for Microsoft.NET v.3.5 — for WPF.

The original code was created using Microsoft Visual Studio 2008 and targeted for Microsoft.NET 3.5. For compatibility with .NET v.2.0, two of the projects were re-created for Window 2005 and tested (apparently, WPF sample could be not supported for v.2.0), see “Projects.2005”. Any of two different solutions, “FirstTime.2008.sln” or “FirstTime.2005.sln” can be used to build the code using respective versions of Visual Studio.

In fact, Visual Studio is not required for the build, as the code can be built as batch through running the batch file “build.v.2.0.bat” or “build.v.3.5.bat”. One will need to edit the batch file to support another version of the platform. Another option is to use SharpDevelop.

Conclusion

Thank you for your interest. I hope you find the techniques useful or just interesting enough; if not, I hope you have had some fun: elimination of the boring work was my primary goal.

I would love to get your feedback.

Credits

Based on the previous version of my code, Paulo Zemek pointed out the problem with garbage collection (see above) as well as the potential problems with thread safety. His notes helped me to re-think parts of implementation related to threading and per instance behavior.

Roberto Guerzoni found a critical bug which I fixed in v.2.1 of September 5, 2014. That was the regression bug in the code of non-diagnostic version of FirstTime; when the per-instance “first time“ behavior was implemented, I forgot to replace one reference to the dictionary, which led to the dictionary key exception. Roberto provided the exact offending code fragment where the bug was clearly noticeable by an unarmed eye. Thank you very much, Roberto!

It's less known in Western world, but it is fundamentally well-known in the sphere of influence of cultures related to Farsi and Arabic languages and beyond. He is considered as a national poet at least in Iran, Tajikistan, Uzbekistan (where the language is Turkic) and Afghanistan. In Russia, all educated people know at least the name. I'm almost sure that it you read some text, you will find them very familiar. What, never heard of Rustam and Zohrab, "Shahnameh"? Hard to believe...

You can see how it's done from the article or source code. This is not the system for continuation of the execution, but even if it was, I would be come close to the idea of contamination of the Registry, it would be a completely wrong thing to do. By the way, did you pay attention that — finally — Microsoft people started to discourage to writing into Registry, even installation. Self-installing applications not contaminating in the Registry are the best; and .NET provides good support for it…

None of those, rather a recurring series of nightmares! An int counter or a timer alone are already very cheesy, still not the worst things - in a badly designed system once I had to write a specialized piece of "aritifical intelligence" that found out when to execute the magic initializer functions of our newly added features. All stars had to be at the right angle to avoid the crash. Unfortuantely this is quite common with huge old legacy codebases where the whole stuff is lava code and the initialization and object lifetime management is screwed up badly. Fortunately over the years I developed my skills to be able to avoid jobs that are only about the maintenance and patching of such systems without applying some refactorization and code beautification...

I understand that quite well. In my case, rather such jobs avoided me all the time, from the very beginning , but a reasonable job here in US is damn rare, almost all people forge complete trash. If I do everything myself and have a rare chance to work with good people, it goes a lot better, and there is a little hope for legacy, so a lot of job is done from scratch, but not all companies were able to get the sales before the lost business…

Just stumbled into this article from the front page, and I'm impressed. Been using a lot of _firstActivation flags in my WPF-based system to initiate background jobs, and this could really clean that up. Great job!

Initially, this work was planned more to demonstrate a possibility of using very exotic (but reliable, based on standards) technique for solving trivial problems, almost a joke; I did not expect so good acceptance of it.

To give you a five I still want one correction.
You are using a ReaderWriterLockSlim, but you never use a ReadLock.

If you are not using read-locks, there is no reason to use UpgradeableLock (as 2 upgradeable locks are mutually exclusive). In fact, it is better to use the lock keyword, with is simpler to use, faster to create (a simple object is enough) and faster to acquire/release.

Also, you don't need a dictionary to store a value of 0. Use a HashSet instead (it is indexed as the dictionary, but does not stores a value... you can call Add directly and the Add returns true if the value was added, false if it was already there, so you can avoid a first search to then add.