Wednesday, December 10, 2008

C# odditiy: Object initializer scope

I was reviewing some code today and ran across something that looked like this:
SomeProperty = SomeProperty

Odd, I thought that doesn't do anything, probably not what the writer intended. I sort of ignored it since I was doing some refactoring that removed that line anyway and went on. When I realized I didn't have any tests covering this bit of code, I saved my changes, reverted the unit, wrote a test and ran it, expecting a failure. Much to my surprise, it worked.

In context, the function looked sort of like this:
public class SomeClass
{
    public string SomeProperty { get; set; }

    public object Clone()
    {
        return new SomeClass { SomeProperty = SomeProperty };
    }
}

Looking at this, I expected both the SomeProperty properties to be in the scope of the object initializer and end up not doing anything, essentially assigning the property to itself. The test seemed to indicate otherwise. Thinking I had a problem with my test, I set some breakpoints and did some evaluation at run-time. I didn't see anything wrong with the tests and everything seemed to be working.

Still convinced something had to be wrong, I did some searching on the web trying to find somebody who talked about scoping rules in object initializers. Of course, I may not have hit on the correct search terms, but in any case I didn't find anything. So I wrote the following console application:
namespace TestObjectInitializerScopeConsole
{
    public class TestClass
    {
        public string TestText { get; set; }
    }

    class Program
    {
        public static string TestText { get; private set; }

        static void Main(string[] args)
        {
            TestText = "Some random text";
            Console.WriteLine("this.TestText = \"{0}\" (initially)", TestText);

            var test1 = new TestClass();
            Console.WriteLine("test1.TestText = \"{0}\" (without initializer)", test1.TestText);

            var test2 = new TestClass { TestText = TestText };
            Console.WriteLine("test2.TestText = \"{0}\" (with initializer)", test2.TestText);

            Console.WriteLine("Enter to finish...");
            Console.ReadLine();
        }
    }
}

According to this test, it seems to indicate the scope for items on the left hand of the assignment are the new object and those on the right hand are what you'd normally expect for the method. It seems pretty odd and anti-intuitive to have different scope like this.

Any comments? Am I missing something? Is this defined somewhere that I've missed? Does it seem weird to anyone else?

Friday, December 5, 2008

How to show WWSGD text in Blogger

I've been doing quite a bit of reading regarding the ins and outs of blogging, search engine optimization and building readership. In the course of this, I read 21 Ways to Make Your Blog or Website Sticky. In that article, Darren Rowse mentioned a WordPress plug-in by Richard Miller called What Would Seth Godin Do. Based on an observation by Seth Godin, this plug-in allows customized messages to viewers based on the number of times they visit your site.

Intrigued by this idea, I set off to find something similar for Blogger (a.k.a. Blogspot) based sites. After a lot of searching, I failed to find anything. I figured it couldn't be too hard; I'd just roll my own. It took a bit more work than I expected, but I finally came up with my own variation. There is no code shared at all with the WordPress plug-in; it's simply similar functionality inspired by Seth's observation and Richard's implementation. The following explains how to configure a Blogger site display different text based on a user's visit count.

First, go into the Layout tab for your site and then the Page Elements sub-tab. Click on Add a Gadget. Select the HTML/JavaScript option. In the Content section, place something like this:
<div id="NewVisitor" style="display: none;">Thanks for visiting! Use the RSS feed or e-mail subscription to keep up to date on what's happening on this site.</div>
<div id="ReturningVisitor" style="display: none;">Welcome back! We're glad you enjoy our writing. If you especially like a particular article, please consider casting a Digg vote. Thanks!</div>
I'm no copywriter and obviously you'll want different text, but the important thing is to have two div sections with IDs of NewVisitor and ReturningVisitor, and with a style attribute for both set to display: none;. When the page is loaded, one section or the other will be changed to visible based on the result of a cookie.

Except for the limitations of ID and style, the rest is normal HTML. You can put things that are common to both text sections outside the div sections. Inside the div sections, put things you want displayed for the context identified by the ID attribute.

Save the gadget. Since the text is inside a gadget, you can move it to where you want it to display.

Next, select the code below and copy it to the clipboard. Then go to the Edit HTML section of your blog configuration and scroll down through the template code until you find the line that says <body>. Just above this line, there will be one that says </head>; paste the copied code just above the </head> line.

<!-- Start of script for "WWSGD" div manipulation -->
<script type='text/javascript'>
function getCookie(c_name)
{
  if (document.cookie.length > 0)
  {
    c_start=document.cookie.indexOf(c_name + "=");
    if (c_start != -1)
    {
      c_start=c_start + c_name.length+1;
      c_end=document.cookie.indexOf(";",c_start);
      if (c_end==-1) c_end=document.cookie.length;
      return unescape(document.cookie.substring(c_start,c_end));
    }
  }
  return "";
}

function setCookie(c_name,value,expiredays)
{
  var exdate=new Date();
  exdate.setDate(exdate.getDate()+expiredays);
  document.cookie=c_name+ "=" +escape(value)+
      ((expiredays==null)
        ? ""
        : "; expires="+exdate.toGMTString()+
      "; path=/");
}

function checkCookie()
{
  wwsgd_count=getCookie('wwsgd_count');
  if (wwsgd_count == null || wwsgd_count == "")
  {
    wwsgd_count = 0;
  }
  else
  {
    wwsgd_count = parseInt(wwsgd_count);
  }
  setCookie('wwsgd_count',wwsgd_count+1,365);
  visibleTag = 'ReturningVisitor';
  <!-- This will show the "new visitor" text three times.
      Change 3 to the desired value. -->
  if (wwsgd_count &lt; 3)
  {
    visibleTag = 'NewVisitor';
  }
  divToSee = document.getElementById(visibleTag);
  if (divToSee != null)
  {
    divToSee.style.display = "block";
  }
}
</script>
<!-- End of script for "WWSGD" div manipulation -->

(For those with sharp eyes, JavaScript's less than operator is encoded above. This is by intent. It needs to be encoded in the Blogger template when it is saved. It gets converted to a real less than sign and used properly when it is sent to the client's browswer.)

Finally, on the <body> line, before the closing ">", add onLoad='checkCookie()'. When done, this line will look like:
<body onLoad='checkCookie()'>

When these three things are finished, the site should show the items inside the NewVisitor div section the first three times it is visited. After that, the items inside the ReturningVisitor should be displayed. If you want a different count for the first message, change the numeral 3 in the script (indicated by a comment) to the desired number. If cookies aren't enabled, then nothing will be displayed.

Leave a comment if you have any thoughts or find this useful. Thanks!

Resources

Thanks to the following for information found useful in the development of this tool: