|All blog entries are the opinions of the author and do not necessarily reflect the opinions of their employer. All the code presented is for explanation and demonstration purposes only. Any damages incurred to your site and/or data are not the responsibility of the author. Every effort is taken to ensure the code properly compiles, however sometimes there are some hiccups and you might be required to do your own debugging.
What's the difference between constants and read only fields you ask?
Tuesday, March 24, 2009 11:28 PM
We all know “magic numbers
” are bad in our code. Back in the good’ol days of VB you had constants. In Java you had final variables that were part constant and part read only. Now in C# we have both constants and read only fields. Hhhhmmmm that begs the questions what’s the diff between them then? Read on for more information and code.
We all know “magic numbers
” are bad for us, but do you know what to use instead of hard coding that request parameter variable name? Or what to use instead of typing out “HabsRULE” everywhere then have to do a global search’n’replace for years like this one (the Habs aren’t doing too well :<). Constants and read only fields to the rescue! But what’s the diff between them? Read on for more information.
Short answer: Constant values are "baked" into your assembly and have to be resolvable at compile time. Read only value "get" their value at runtime in their initialize statement or a constructor and have to be resolvable at runtime. It is this "baking" of the values into the assemblies which cause problems when you're "taking" DLLs from third parties and expect certain values "to just pick up the new constant value when you get a new DLL from them."
Constants are great for things which will never, Never, NEVER change. Because NEVER is such a long time :> you have to make sure your constant value will NOT change for the lifetime of the assembly you’re building AND the assemblies which depend on your assembly as well (that's the tough one). Things like PI (~3.14) is a good candidate, the year Microsoft released .NET 1.0 (2002)
:> is another. These things are great to “bake” into your assembly/code cause they’ll never change (have I mentioned yet they don’t change?).
Read only fields on the other hands are great for things that you would like to consider solid (like a constant) but may not necessarily be known at compile time what that value is. The year your company was incorporated, the copyright year, or the first year the Ottawa Senators came into existence (they had two teams actually, one in 1917 and another in 1992). These are things which you are able to initialize when you declare the variable as readonly or in a constructor, but only in a constructor. If you try to do it outside of those two areas, you’ll get a compile error.
These are academic differences, so what's the meat? Or as SG would say, "wheres' the why?" Here it is! When you have a dependency that's using a constant and you update the DLL but don't rebuild/recompile your code/assembly/DLL, you WILL NOT SEE THE UPDATED CONSTANT VALUE. I put that in caps to over emphasis that point.
I've written a small piece of code to help illustrate the differences.
In the solution, you'll find a project called 0-Teams which has the Montreal Canadiens and the Ottawa Senators along with their first year in the NHL and date of first game played.
Next you'll see two projects which show two different types of assembly dependencies, Project and DLL references. As the solution is build, these will always deliver the same results, the values will always be constistent cause these projects get rebuild when the solution (and therefore Teams assembly) gets rebuild.
The last project, 3-ExternalDLLReference has DLL reference like the previous project BUT this one requires you to copy the Team.DLL by hand. This is to act similarily to the way you would get a DLL from a third party/off the internet/from a buddy and where the main difference between const and readonly fields will show itself!
Once you compile the solution, manually copy the Teams.dll and Teams.pdb file into the ExternalDependencies directory. Steps 1, 2 and 3 are required for the first time you build the third project, and step 4 is for after you make changes (it's coming, dont' worry :>).
Once you've done that, manually build the 3-ExternalDLLReference project and then run it. Everything's good and all is happy. Now, pretend a few decades have passed and now the Ottawa Senators have come and gone, and now are back! Well, now you want to change the settings in Senators right? So let's go change the FirstYear and FirstGame values (comment and uncomment out the appropriate variables, I don't really need to tell you how to do that right?).
Now, let's recompile the solution and rerun the first two projects. All is still good and consistent. Shouldn't be a surprise cause the constants are "rebaked" into the exe we're running in both cases.
NOW! Copy the new compiled Team.* files again, but afterwards don't recompile! Since we're NOT recompiling, you'll have to drop the file into the bin\debug directory for the runtime to see it (step 4 from above). We're trying to simulate a third party giving you a new DLL and you just dropping it into your environment and seeing what happens. If you don't see these changes now, the chances are pretty good you didn't drop the file in the right place, didn't compile or didn't make the change and then recompile the Team project.
You'll notice how the YearFounded remains 1883 when we might be expecting it to be 1992! But the first game date is properly updated as expected. That's the BIG difference between using a const and a readonly field, not actually using them but when you depend on them a bit too much! :>
So now that you know the differences between constants and readonly fields, you won't get caught in a similar situation as described above. Now go grab a coffee and get coding! :>