2011-12-31

C# Blooper №1: No warnings about uninitialized readonly members when the class is public and the member is public, protected or protected internal.


Before reading any further, please read the disclaimer.

The C# compiler is kind enough to give you a "field is never assigned to" warning if you forget to initialize a readonly member which is private or internal, or if the class in which it is being declared is internal. But if the class is public, and the readonly member is public, protected or protected internal, then no warning for you! Why, oh why?

namespace Test1  
{  
    class Test1 
    {  
#if TRY_IT  
        public readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        protected readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        internal readonly int o; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        private readonly int p; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        protected internal readonly int q; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
         
        Test1() 
        { 
            if( p != 0 ) //To avoid warning 'The field is never used' 
                return; 
        } 
#endif 
    }  
  
    public class Test2 
    {  
#if TRY_IT  
        private readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        internal readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
 
        Test2() 
        { 
            if( m != 0 ) //To avoid warning 'The field is never used' 
                return; 
        } 
#endif  
        public readonly int o; //Blooper: no warning about field never assigned to.  
        protected readonly int p; //Blooper: no warning about field never assigned to.  
        protected internal readonly int q; //Blooper: no warning about field never assigned to. 
    }  
  
    public sealed class Test3 
    {  
        public readonly int m; //Blooper: no warning about field never assigned to.  
    }  
}  

For a moment you might think "well, a descendant might initialize that member", but that theory does not hold any water, for a number of reasons:
  • Internal classes may also be subclassed, but the compiler does not fail to issue the warning in their case.
  • Sealed classes may not be subclassed, but the compiler fails to issue the warning in their case, as Test3 in the sample code demonstrates.
  • The warning makes sense for the sake of the integrity of the base class regardless of what a derived class may or may not do.
  • Lastly but most importantly, the C# specification expressly prohibits a derived class from initializing a readonly member of a base class. You get Error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer) which, incidentally, is a little bit misleading, because you may be trying to assign the field from within a constructor, only it is the constructor of the wrong class.
According to MSDN Documentation about this warning, the exhibited behavior is to be expected:
Compiler Warning (level 4) CS0649:
Field 'field' is never assigned to, and will always have its default value 'value'
The compiler detected an uninitialized private or internal field declaration that is never assigned a value.
The question is: why?

UPDATE:

I posted this question on StackOverflow, and Eric Lippert himself answered it. The short answer is that it is an oversight of the compiler, but the long answer is also quite interesting and worth reading.
-

C# Bloopers


Please do not get me wrong; C# is awesome. It is the language of my choice, even though I am pretty well versed in C++ and Java. That having been said, it cannot be denied that C# has its share of flaws, too. In this series of posts I am documenting some of them, in no particular order.

Also please note that many of the issues described herein are Visual C# bloopers, not C# bloopers in general.

C# Blooper №1: No warnings about uninitialized readonly members when the class is public and the member is public, protected or protected internal.

C# Blooper №2: No warnings about accessing uninitialized members.

C# Blooper №3: No warnings about fields having already been initialized.

C# Blooper №4: Lame/annoying variable scoping rules, Part 1

C# Blooper №5: Lame/annoying variable scoping rules, Part 2

C# Blooper №6: No warnings about unused parameters.

C# Blooper №7: No warnings about unused private methods.

C# Blooper №8: No warnings for conditions that are always true/false

C# Blooper №9: Annoying case statement fall-through rules.

C# Blooper №10: Switch statements are not properly formatted.

C# Blooper №11: Zero to Enum conversion weirdness

C# Blooper №12: 'Where' constraints not included in method signatures

C# Blooper №13: C# Blooper №13: Stack and Queue do not implement ICollection

C# Blooper №14: Weird / annoying interface method visibility rules.

Stay tuned, there is more to come.
-

2011-10-16

Intertwine: Normalizing Interface Invocations

This post has been superseded by a new post in 2022
See michael.gr - Intertwine


This is a C# project that I did back in 2011. It consists of a (rather informal) white paper which describes the project, and a zip file containing the source code in the form of a Microsoft Visual Studio solution.

Here is the abstract:
A mechanism is proposed for converting (entwining) method call invocations of any interface to a general purpose single-method normal form, and converting back (untwining) from the normal form to interface invocations, so that operations can be performed on the normal form in a way agnostic to the interface being invoked. The normal form is a delegate in C# or a functional interface in Java, realized as object AnyCall( int selector, object[] parameters ). A DotNet implementation is provided in C#, though the discussion also applies to Java.

And here is the table of contents:
  • Abstract (page 1)
  • The Problem (page 1)
    •  Why messages are bad (page 2)
    •  What is missing (page 2)
  • The Solution (page 2)
    • A hand-crafted solution (page 3)
    • Automating with Intertwine (page 6)
  • Appendix 1: A note about Dynamic Proxies (page 6)
  • Appendix 2: An example: Interface multicasts (events) (page 7)
  • Appendix 3: Things to fix (page 8)


Download the white paper: Intertwine v2.1.pdf
Download the source code: Intertwine v2.0.zip

2011-09-15

Gerasko Aei Didaskomenos

Solon's original phrase was "Gerasko D' Aei Polla Didaskomenos", but here in Greece we use the shorter form, "Gerasko Aei Didaskomenos". I grow older forever learning new things.

It is never too late to learn something new. For example, just a few months ago I learned of the existence of the "??" operator in C#, after several years of using the language. Of course I had come across that operator in the reference, but it had not occurred to me how useful it would be in real-life scenarios. Then, one day I chanced upon someone else's code making use of it. There was a big 'aha!'.

So, today I learned one of the most useful things I know about Visual Studio.

Let us suppose for a moment that you are a real programmer, not a button-clicker that Microsoft thinks you are. So, when you double-click on a file in the Solution Explorer, what you want to see is the code, naturally. And this is what usually happens. But then one day you start programming Windows Forms, and suddenly double-clicking on some (but not all) of the files in your project does not show the code. Instead, Microsoft believes that what you must want to see in these cases, is, undoubtedly, their spiffy Windows Forms Designer. Because obviously, they think you must be a mindless button-clicker.

So, every time you double-click on a .cs file that happens to contain a form class, you are presented with a great big huge gotcha! as the designer appears before you instead of the code editor, and you are reminded, for the thousandth time, that double-clicking on a .cs file will do vastly different things, depending on what the class inside that .cs file derives from.

So, is there a way to convince Visual Studio to always show you the code instead of the designer when you double click on an item in solution explorer? In other words, is there any way to tell Visual Studio that you are a real programmer and not the button-clicker that Microsoft thinks you are?

It turns out that there is. I found it out today thanks to StackOverflow, (see here and here,) and it really made my day. In short, here it is:

The next time you want to open a .cs file, right-click on it and select "Open With..."; on the dialog that opens, select "CSharp Editor", and then click on the button which says "Set as Default". That's it, it will work forever after for all .cs files.

The only problem now is, that after a couple of years of Windows Forms Programming while being conditioned to always be careful to right-click on forms .cs files and select 'View Code', I have to first unlearn that before I can start double-clicking freely again.

Cheers!

2011-06-11

Preventing a file from being committed if it contains a certain keyword

If you are a developer with any real-world experience to speak of, you have undoubtedly come across the following situation: you made a change which was not meant to be committed, (for instance, some debug statement or some mock-up of functionality meant to be filled-in later,) and then you forgot about it and went ahead and committed all of your code. This mishap can be a cause of severe frustration for your fellow co-workers, and the source for memorable "WTF moments" for the QA department.

Now, if you are like me, you like to automate things. Why should I have to remember to do something on my computer, when my computer can be tasked with reminding me to do it? Is a computer the ultimate automation tool or not?

The interwebz abound with questions on precisely how to achieve this bit of automation:

In short, if you are using SVN, here is how to do it:

Have a pre-commit hook in the repository which checks to see whether any file contains the string NOCOMMIT, and if so, it fails the commit.

So, when I alter a source file in a way which is not meant to be committed, I append a //NOCOMMIT comment right next to each change, and I do not have to worry about it anymore. If I do accidentally attempt to commit it, the pre-commit hook of the repository will block my commit and let me know which files contain the NOCOMMIT  keyword, so I can go into each one of those files and fix it.

I find this feature so useful that I honestly even use it when programming at home, where obviously, I am the only programmer in the team.

If you are using SVN on windows, you can paste the following into a file called pre-commit.bat in the hooks folder of your SVN repository:

:: Stops commits that contain the NOCOMMIT keyword.
setlocal
set REPOS=%1
set TXN=%2
SVNLook diff %REPOS% -t %TXN% | findstr /I /M /L NOCOMMIT > nul
if %errorlevel% gtr 0 (
    exit 0
) else (
    echo Your commit has been blocked because it contains the keyword NOCOMMIT. 1>&2
exit 1
)

With SVN on Unix systems, something like the following will do the trick, though please note that I have not tested it.  (Note: suggestions from a comment by Georgi have been applied.)

#!/bin/sh
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/local/bin/svnlook

$SVNLOOK diff -t "$TXN" "$REPOS" | grep -i "NOCOMMIT" > /dev/null && { echo "Your commit has been blocked because it contains the keyword NOCOMMIT." 1>&2; exit 1; }

2011-05-29

Wonderful MSBuild

So, for some time now, whenever I try to 'batch build' from within Microsoft Visual Studio 2010, I get the following error:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(2868,9): error MSB3021: Unable to copy file "x\Intermediate\y.dll" to "x\y.dll". Could not find file 'x\Intermediate\y.dll'.

Indeed, there is no file 'x\Intermediate\y.dll'. But when I switch configurations and try to build the regular (non-batch) way, it builds fine.

Amused, and since I can live without the batch-build functionality, I have just let it be all this time, writing it off as one more of those weird wonders of Microsoft.

Then today I figured out what the problem was. I am to blame, because I brought this upon myself. And I brought it upon myself while trying to circumvent some other, even more wonderful, weird wonder of Microsoft.

My MSBuild woes begun years ago, on my very first day of C# programming, when I saw those "bin" and "obj" directories in my project folder, and my first reaction was, of course, to want to make them go away.

There is an option in project properties to set the output folder, but not the intermediate folder. This takes care of the "bin" folder, but the stupid tool keeps creating an "obj" folder under the solution folder and puts all intermediate files in there, no matter what.

As you might understand, I decided that I just would not have any of that shit. I was determined to never write a single line of C# if I did not first find a way to make that annoying obj directory go away.

Needless to say, on my first day of C# programming I did not write any C# at all. I just banged my head against the keyboard triyng to find a way to get that folder to go away.

After a lot of googling around, I discovered allegations about the existence of some <IntermediateOutputPath> tag that goes inside a project file. So, I edited the .csproj file with my text editor and after each <OutputPath> tag I inserted an <IntermediateOutputPath> tag as follows:

<IntermediateOutputPath>x\Intermediate\</IntermediateOutputPath>

(where x is my output path.)

Now, MSBuild would put the intermediate files in the folder that I specified, but it kept ALSO putting them in "obj" under my solution folder. That was just mind-blowing.

So, I took a drastic measure: I deleted the "obj" folder and I created an empty text file called "obj" in its place, which I marked as read-only and hidden, and I added it in the ignored files in SVN.

Strangely enough, this awful hack worked. Or at least it appeared to work. Just today I realized that it worked for the regular build, but it has been the reason why my batch-build does not work.

So, it appears that the only way to have batch-build functionality in Visual Studio is to resign to having a stupid "obj" folder under your project folder. Oh, well!