the static class in C# 2.0 is better than you think!


Fully unrelated to Hatteras, but a C# developer whohas been playing around with the beta was attempting to point out (incorrectly that the “static” modifier to a class was just syntax sugar and no better than making a private default constructor that was never called from the class itself (perhaps one that just did a “throw new NotSupportedException();”)  Not that it’s a huge deal or a normal situation (priv requirements being what they are, IIRC), but a static class is indeed better for preventing instantiation.  Others have already shown this (and I intended to just link to one of them) but my google karma must have been running low today, so here’s a quick little proof:

using System;

using System.Reflection;

 

public class Program

{

    static void Main(string[] args)

    {

        Type ncType = typeof(NeverConstructed);

        ConstructorInfo constructor = ncType.GetConstructor(

            BindingFlags.CreateInstance |

                BindingFlags.NonPublic |

                BindingFlags.Instance,

            Type.DefaultBinder,

            Type.EmptyTypes,

            null);

        constructor.Invoke(new object[0]);

    }

}

 

public class NeverConstructed

{

    private NeverConstructed()

    {

        Console.WriteLine(“NeverConstructed got constructed!”);

    }

}

 

As you’d imagine, a static class would never allow the above – “error CS0710: Static classes cannot have instance constructors”.  Of course, I hesitate to post this because of the usual set of people that freak out as if the above were some kind of security hole (as they typically do when the above is presented to .NET user groups), but just as people learn to actually read dialogs before click Ok (IMHO :), developers need to learn that “private” doesn’t mean “secure and safe from the eyes of others” – if you need to protect the data, use the Data Protection API :)  I’m sure I’ll get some good comments on this one :)

 

On an even more unrelated note, if you haven’t already, make sure to check out the Power Collections spec – there’s some very promising work that Peter (rss) is doing there – very exciting stuff!  I had gotten spoiled with a lot of the stuff in the Jakarta Project’s Commons Collections in my work past, so this is good to see developing.


Comments (2)

  1. Hi says:

    The question was, how is a static class better than a private constructor that does "throw new NotSupportedException();"? Your proof did not address the question.

  2. Yeah, my main goal was just to do the whole "private doesn’t mean inaccessible" thing and I didn’t want to babble on for too long, but that’s a valid question, of course.

    The main benefit in my mind (and since this gets into subjective opinions, I wanted to keep it out of the post) is intention. With Whidbey partial classes and large classes in all versions, it can be very hard to tell what’s going on in a large class or one that’s split among multiple files.

    Imagine a Helper class that’s split among 2 files helper-web.cs and helper-db.cs – say the split was added to help reduce source conflicts as the db devel team and web devel team do their work. (The same kind of split happens with forms (by default) in Whidbey with .cs and .designer.cs files). The web team decides since their usages of Helper never need instance variables, they’d like to make sure it’s not instantiated, so they throw in the private constructor with the exception throwing. The db guys aren’t affected by just this, though – they’re still free to make all the public constructors they want, add instance vars, etc. While the web guys had the intention of getting a never-instantiated class, there was nothing they could do in their file to limit that. Same goes for large files. If I’m editing a large class (I wasn’t the primary developer on) and the chunk I’m working on doesn’t happen to be near source-wise to the private constructor with the exception thrown, it may not occur to me that adding a couple of instance vars and a public constructor is a bad idea. Maybe I happen to notice the existing stuff is static, but that’s asking for a human to notice such a pattern, not asking a compiler to enforce something.

    The key point is that putting the static decorator on the class allows for specification of intention. If the helper-web guys throw static on their class decoration and the helper-db guys don’t have it, they’ll get a compile-time failure, which is far better than run-time behavior that’s not what the web guys were expecting (and behavior they may never figure out is even happening, since it’s unlikely to break them).

    The static decorator conveys both to the compiler and to other developers that this class should never be instantiated and by no longer relying on the human to enforce that pattern, developers have more freedom to not have to track that information themselves – if they forget, the compiler lets them know better.

    Also, worst-case scenario – which is less keystrokes to enforce the never-instantiate rule? static’s going to be 7 keystrokes to shove in the "static " and the private constructor will be more, even with Intellisense helping out :) (yeah, yeah, barring a macro just for that kind of constructor). More pragmatically, I never want to instantiate this class – why should I have to write a constructor at all, even if its an intentionally broken one? :)

    I’m sure there will be people that continue to use private-ctor-that-throws and whatever works for them is fine by me, I just mainly wanted to point out that the static decorator may look like just syntax sugar, and it’s arguable that it is, but it helps convey intention better than a private constructor that may or may not be on the same screen when you’re editing code.