Skip to content

2008

Struct's via Automatic Properties can be tricky

Here's a bit of code i just got through debugging...

public Point Point { get; private set; }

public void Offset(Point origin)
{
  Point.Offset(-origin.X, -origin.Y);
}

Can you tell what's wrong here? Let's just say that the Offset won't take.

structs are value types, which means anytime you pass one around you get a new copy. So far so good. And that means when you expose a struct value via a property, the accessing party always is looking at a copy. Again, fine, after all when you do a set you change the stored value and if you need to manipulate it, you just manipulate the actual struct.

Enter Automatic properties and you might forget about this last detail and not realize that you never get access to the underlying value, even from within the class. I.e. when I call Point.Offset, i'm calling it on the copy that was passed to me and the resulting value is immediately thrown away. So i just went back to using the property to facade a private Point, which i can now manipulate inside of Offset. Duh.

More Deferred Execution Fun: foreach and delegation scope

This is closely related to my last post on deferred execution gotchas and its basically more "if you inline delegated code, you may easily overlook scope side-effects". This time it's about dealing with foreach and using the local each item for deferred execution.

public void SpawnActions()
{
  foreach (ActionContext context in contexts)
  {
    int id = context.Id;
    Action<int> callback =  
      (workerNumber) =>
      {
        Console.WriteLine("{0} Id: {1}/{2}", workerNumber, id, context.Id);
      };
    ThreadPool.QueueUserWorkItem(new WaitCallback(FutureExecute), callback);
  }
}

public void FutureExecute(object state)
{
  int id = worker++;
  Action<int> callback = state as Action<int>;
  Thread.Sleep(500);
  callback(id);
}

The output looks like this:

0 Id: 0/9
1 Id: 1/9
2 Id: 2/9
3 Id: 3/9
4 Id: 4/9
5 Id: 5/9
6 Id: 6/9
7 Id: 7/9
8 Id: 8/9
9 Id: 9/9

So while the foreach scope variable context is kept alive for the deferred execution, it turns out that foreach re-uses the variable on each pass through the loop and therefore when the Action is later executed, each one has a reference to the last context. So what we need to do is create a true local variable for context so that the lambda's scope can hold on to the reference we want.

foreach (ActionContext context in contexts)
{
  int id = context.Id;
  // locally scoped variable
  ActionContext c2 = context;
  Action<int> callback =  
    (workerNumber) =>
    {
      Console.WriteLine("{0} Id: {1}/{2}", workerNumber, id, c2.Id);
    };
  ThreadPool.QueueUserWorkItem(new WaitCallback(FutureExecute), callback);
}

And now our results are a bit more what we expected:

0 Id: 0/0
1 Id: 1/1
2 Id: 2/2
3 Id: 3/3
4 Id: 4/4
5 Id: 5/5
6 Id: 6/6
7 Id: 7/7
8 Id: 8/8
9 Id: 9/9

Copying a Silverlight User Control from one project to another

Here's something I tracked down with no help from error messages:

When you copy a user control in Silverlight 1.1 from one project to another the Xaml that the control loads will have it's Build Action set to SilverlightPage. When you then run your project and try to create an instance of that control you'll get the ever so informative AG_E_INVALID_ARGUMENT. All you need to do to fix it, is set the Build Action to Embedded Resource again. Tada!

I love declarative definition of UI with behavior wired to static code. But man, at its current state, the debugging support for it just isn't there. I mean it's bad enough that having strings in the declarative side to link to actions that won't be updated by normal refactoring, nor will they show up as references, but at this state Xaml brings the worst part of scripting languages to compile-time checked coding:

Vague runtime errors without a stacktrace

Bah.

XP on Bootcamp & VMWare Fusion, take 2

Time to re-install XP

My setup until yesterday was Bootcamp partion that was running as a VM using VMWare Fusion. The Bootcamp partition was set up as FAT32, because I NTFS came up as readonly when mounted under Mac OS.

Then I started up another VM (Fedora Core 7, although i have since noticed it's not what OS you run, but just a second VM). Maybe it's not enough memory, maybe it's a VM running from bootcamp plus a VM running from a disk image, but while it had worked previously, this time, it locked up my Mac hard. I finally had to hard boot the Mac. When I got back into th VM, I noticed things were broken. Now, I've had to hard boot XP many times and I've never seen this. An indeterminate number of files were corrupted. I noticed one XML file that halfway through turned into binary garbage, so I assume that the other systems failing were suffering from similar corruption. Basically it was hosed, because there was no way to determine what had been corrupted. Time to re-install.

Bootcamp & VMware install

Looking at my post from last time, it was clearly written with the frazzled recollection of a day of trying to make things work, since i once again ran into problems. This time I'm making sure I write the resolution down.

  1. Imaged the old partition, because you always realize that you forgot to back up some vital file.

  2. Removed the old partition and created a new one (using the Bootcamp tool), this time large enough for more than just fallback use (since it's used daily under VMWare). This creates a FAT32 partition.

  3. Inserted my install disk and Bootcamp restarted to fire up the windows install. Important note here, this has to be a real XP install disk. I first tried to use my MSDN DVD with the chooser for picking what OS to install. However, the Mac keyboard doesn't seem to work when you get to the menu. So I used an XP Pro w/ SP2 CD and rebooted. Now the installer ran just fine

  4. Formatted the partition using NTFS. Even if you use FAT32, re-format, don't use the Bootcamp formatted partition. At least for me, using that prepared partition didn't work and created an unbootable image. I know NTFS cannot be written to by MacOS, but it doesn't really matter, since once I boot it as a VM, i can always transfer files via loopback file sharing. I'm going NTFS to get a journaling file system. Theoretically that should prevent the corruption I got last time.

  5. After the install completes, pop in the Mac OS disk and let it install the Bootcamp utilities. This gives you full support for the Macbook Pro hardware.

  6. Activate Windows and reboot into Mac OS X.

  7. Fire up VMWare Fusion. Bootcamp partition should be listed as a VM. Since I previously had a bootcamp partition, I had to go into Library::VMWare Fusion::Application Support::Virtual Machines and remove the old Bootcamp partition folder. Fusion will then do its magic and prep the Bootcamp partition to run as a VMWare Image.

  8. Activate Windows again. That should be the last time you have to do it.

Let's hope this doesn't turn into a bi-monthly process :)