Wimdows.NET

Wim's .NET blog

  • Dump the Module keyword in VB.NET!

    Though I'm mainly a C# developer, I now and then get exposed to some VB.NET stuff. No, this is not going to be a C# vs. VB.NET debate. We've seen enough heated arguments and flame wars on that topic over the years.

    Something about VB.NET Console applications created in Visual Studio.NET (all versions), bugs me though: the dreaded Module keyword. The default skeleton for a Console app in VB.NET looks like this:

    Module Module1
        Sub Main()
        End Sub
    End Module


    Whilst under the hood, a module is simply a class with static members and a private default constructor to prevent instantiation, I don't think its use should be promoted like that. And I really wonder why MS hasn't changed the default Console app skeleton to look as follows:

    Class Program
        Shared Sub Main()
        End Sub
    End Class


    In my opinion, the Module keyword shouldn't have even existed in VB.NET. It's one of the reasons why a lot of VB.NET code I've seen simply gets dumped in a Module, and Object Oriented Programming goes out the window. Of course, there's nothing stopping you coding like that in VB.NET without using the Module keyword, or even in C# for that matter. But it is a step in the right direction in trying to get developers to think about object oriented class design first (static/shared vs. instance members etc), before shoving anything and everything in a Module.

  • Zune MP3 player - DRM'ed or not?

    Here's a question for a debate. Do you think Microsoft's upcoming audio player, dubbed Zune, will play only DRM compatible content?
     
    If that is the case, I won't be touching it with a barge-pole; same reason I haven't got myself an iPod.

    If I have legal MP3 files, ripped them from CD's I own or bought them legally I feel I should be able to play this on however many devices I want, as long as I own them. That means my MP3 player, my phone, server, desktop, laptop, you name it - without restrictions.

    If Microsoft wants to have an edge over the IPod, they need to make sure it works without DRM mangled content. If not, it will flop. Big time.

    What do you guys think? 

  • ViewState, CheckBox, ControlState...errr...

    J. Michael Palermo writes about the CheckBox in ASP.NET maintaining its state regardless of the EnableViewState attribute to False in ASP.NET 2.0.

    Hang on - isn't that the same in ASP.NET 1.0 and 1.1? Oh yes.

    All web controls that implement the IPostBackDataHandler maintain their basic 'value-state' (for lack of a better description) using the HTTP POST form collection. Irrespective of setting the EnableViewState property for the web control to False.

    Nothing has changed in ASP.NET 2.0 as far as that is concerned. The CheckBox control along with TextBox and other controls that implement the IPostBackDataHandler interface, still maintain their basic value-state using their respective HTTP POST values. ControlState has nothing to do with this.

    ControlState is a way to allow more fine-grained control over individual portions or behavioural elements of a web control, which under the bonnet actually still uses the ViewState statebag. Fritz Onion's article outlines this nicely and in more detail.

  • Generic Parse method on Enum - a solution

    David Findley writes about how he wishes we had a generic Parse method on the Enum class in .NET 2.0.

    Though I agree in principle, it's actually quite trivial to create a generic static class with a Parse method, which alleviates some of the pain.

    Here's my stab at it:

        public static class EnumUtil<T>
        {
            public static T Parse(string s)
            {
                return (T)Enum.Parse(typeof(T), s);
            }
        }


    Say we have the following enum:

        public enum Color
        {
            Black,
            White,
            Blue,
            Red,
            Green
        }

    We can now simply use the generic EnumUtil class as follows:

    Color c = EnumUtil<Color>.Parse("Black");

    I feel that this helper method doesn't actually warrant a class in its own right, so you may want to add it to one of your Util classes (if you happen to have a generic one!) instead.

  • ArraySegment Structure - what were they thinking?

    From the MSDN docs:
    ArraySegment is a wrapper around an array that delimits a range of elements in that array. Multiple ArraySegment instances can refer to the same original array and can overlap.

    Turns out this structure doesn't even deserve the definition 'wrapper'. It simply takes the array, offset and number of elements in your segment, and sets a few properties accordingly.

    Subsequently when you want to iterate over the items in your ArraySegment, you still need to use a combination of Offset and Count to achieve this. How is this different from not creating an ArraySegment and define your Offset in-situ as well as the number of elements?

    I was expecting to be able to do something like this:

    ArraySegment<string> seg = new ArraySegment<string>(new string[] { "John","Jack","Jill","Joe"},1,2);
    // Access first item in segment
    string first = seg[0];
    // Iterate through ArraySegment
    foreach (string s in seg)
    {
        Console.WriteLine(s);
    }


    Turns out you can't. There's no indexer for ArraySegment and no enumerator. You have to access the .Array property and use .Count and .Offset as passed to the constructor. What is the point of that!?

    So I rolled my own generic DelimitedArray class which does exactly that. See the inline code below.

        public class DelimitedArray<T>
        {
            public DelimitedArray(T[] array, int offset, int count)
            {
                this._array = array;
                this._offset = offset;
                this._count = count;
            }

            private int _offset;
            private T[] _array;

            private int _count;
            public int Count
            {
                get { return this._count; }
            }

            public T this[int index]
            {
                get
                {
                    int idx = this._offset + index;
                    if (idx > this.Count - 1 || idx<0)
                    {
                        throw new IndexOutOfRangeException("Index '" + idx + "' was outside the bounds of the array.");
                    }
                    return this._array[idx];
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                for (int i = this._offset; i < this._offset + this.Count; i++)
                {
                    yield return this._array[i];
                }
            }
        }


    Hope this is of use to someone.

  • ASP.NET 1.1 server control for <link> - enabling relative URL paths using tilde "~"

    Here's a simple - but useful Link webcontrol class that supports the "~" tilde syntax for relative paths for the href attribute of the <link> element.

    [DefaultProperty("Text"),ToolboxData("<{0}:Link runat=server Href=\"\" Rel=\"Stylesheet\" Type=\"text/css\"></{0}:Link>")]
    public class Link : System.Web.UI.WebControls.WebControl
    {
        private string _href;

        public string Href
        {
            get { return _href; }
            set { _href = value; }
        }

        protected override void Render(HtmlTextWriter output)
        {
            output.WriteBeginTag("link");
            output.WriteAttribute("href",base.ResolveUrl(this.Href));
            foreach (string key in this.Attributes.Keys)
            {
                output.WriteAttribute(key,this.Attributes[key]);
            }
            output.Write(HtmlTextWriter.TagRightChar);
            output.WriteEndTag("link");
        }
    }

    You can then simply drop it in the <head> section of your page (provided you've used the Register directive to register the assembly):

    <cc1:Link id="Link1" runat="server" Type="text/css" Rel="Stylesheet" Href="~/my.css" myattribute="Whatever"></cc1:Link>

    The reason I had to roll my own is that when you add runat="server" for the <link> element, it turns into a HtmlGenericControl instance on the server, which is obviously used for numerous HTML elements, and as such no specific path resolve mechanism is applied to any of its attributes, since the attributes are different per HTML element.

    Hope it helps someone out.