Category / Coding

C# Quines 2009/07/02 at 11:34

Writing quines is a fun way to while away an afternoon, especially when trying to make them as short as possible. This is the result of my attempt at writing the shortest C# quine possible (155 characters,
source file):

class q{static void Main(){string s="class q{{static void Main(){{string s={0}{1}{0};System.Console.Write(s,'{0}',s);}}}}";System.Console.Write(s,'"',s);}}

PS: I came across a shorter C# 3.5 quine (149 characters), which uses var instead of string. Clever. Oh well, c’est la vie.

Crouching Enumerator, Hidden Boxing at 11:13

A few months ago, I was playing around with a simple C# permutation generator to build a word list, with each character position having its own list of characters to iterate through:

List<T>.Enumerator enumerator = characterList.GetEnumerator();

while (condition) {
	if (!enumerator.MoveNext()) {
		enumerator.Reset();
		enumerator.MoveNext();
	}

	Consume(enumerator.Current);
}

Oddly, I was getting a compilation error on line 5, as enumerator doesn’t have a Reset() method despite the IEnumerator interface defining one. MSDN quickly cleared things up, though, revealing that List<T>.Enumerator explicitly implements the method as void IEnumerator.Reset(), which is implicitly private. You can still call private interface methods if you first cast to that interface, so I changed line 5 to the following:

		((IEnumerator) enumerator).Reset();

I thought that was the end of it, but bizarely, the second call to MoveNext() on line 6 also returns false. I confirmed that the private Reset() method actually implements reset functionality, which it certainly does, yet it seemed to have no effect.

The answer lies in the fact that List<T>.Enumerator is a struct. This means that behind the scenes, the cast to IEnumerator is creating a boxed copy of enumerator, and that’s what’s being reset. The original is left untouched, so the call to MoveNext() will naturally return false. Rather than trying to keep the boxed copy that you get from the cast, the correct solution is to use IEnumerator<T> from the outset, rather than List<T>.Enumerator:

IEnumerator<T> enumerator = characterList.GetEnumerator();

while (condition) {
	if (!enumerator.MoveNext()) {
		enumerator.Reset();
		enumerator.MoveNext();
	}

	Consume(enumerator.Current);
}

All this drama could have been avoided if I hadn’t checked the return type for List<T>.GetEnumerator() and used that. So much for more explicit typing being helpful.

Still, it’s rather odd that List<T>.Enumerator is both public and a struct. The former encourages its direct use, and the latter results in the problem I was experiencing. Sadly, this design is constant throughout the System.Collections.Generic namespace. By contrast, the equivalent non-generic collection is ArrayList, and there, the GetEnumerator() method returns an IEnumerator, which is implemented by a private class nested within the ArrayList type – a design that is constant throughout the rest of the System.Collections namespace, and is, in my opinion, better for everyone.

The Joy of ASP.NET, Visual Studio and Proxies 2009/07/01 at 16:11

Some time ago, the web project I was working on started refusing to open. Every time I tried to reload the ASP.NET project, Visual Studio (In this case, VS.NET 2003, but it may affect 2005 and 2008) gave a strange error message:

The Web server reported the following error when attempting to create or open the Web project located at the following URL:
‘http://Localhost:/xyz/ACME.XYZ.Widget’. ‘The connection with the server was reset’.

The project files hadn’t changed and I hadn’t made any changes to IIS recently. In my search for a solution, I come across someone else having problems creating ASP.NET projects from Visual Studio on a network that used a proxy, getting the message ‘A connection with the server could not be established’ – this proved to be the key to the answer. In short, Visual Studio needs to support environments where your ASP.NET project is not hosted on your own machine, so it uses the system’s proxy settings.

In my case, under Control Panel > Internet Options > Connections > LAN Settings…, I had enabled Use a proxy server for your LAN but had neglected to also tick the Bypass proxy server for local addresses checkbox. When Visual Studio gave the proxy a request for localhost, the proxy responded by closing the connection, and thus Visual Studio came back with the error message. Simple, logical, and entirely frustrating.