Thursday, February 26, 2009

Visual Studio Settings Don't Seem to Hold!

So a coworker found this wonderful link on saving Visual Studio settings in a macro, so I thought I'd implement it. I use dual-monitors at work, so I adjusted all of my nice little floating windows on my right monitor, and left the text editor portion on the right. Then I saved my settings because I was so fond of them.

Everything was working great until I started up another instance of Visual Studio and reloaded the settings I saved. For some reason, which I couldn't figure out immediately, the windows in the right monitor were somehow offset from where they should be. All of them were a few pixels to the right. This really upset me.

As I started fiddling around with the window, I found that when I restored the window, moved it a little bit, maximized it again, and then reloaded the settings, the windows on the right moved also.

Moral of the story:

Always make sure the top left corner of your main Visual Studio window is properly placed against the top left corner of your screen when you decide you want to save your settings. If you need to reload your settings at some point, you would also make sure the top left corner of the restored Visual Studio window is in the top left corner of the screen before reloading the settings, and everything will get put in the right place.

Saturday, February 14, 2009

Preventing Duplicate Subscriptions to Your Events

Occasionally a question will come up regarding how to avoid duplicate subscriptions to specific events within classes that have been declared. The typical answer is to tell the reader that they can simply get in the habit of unsubscribing to the event immediately before resubscribing to the event. This situation would look like the following:


Widget.Event -= new EventHandler(HandleEvent);
Widget.Event += new EventHandler(HandleEvent);

While this typically will work fine, mainly because there is no error thrown when the code calls to unsubscribe an event handler that doesn't exist in the event before the call, calling this unsubscribe repeatedly may be unnecessary, and may not be perfectly feasible, especially considering that assemblies shipped as third party assemblies may be used by developers who aren't familiar with this subtle trick of event handler management.

Thankfully, unbeknownst to many developers out there, you can define the behaviors of your add and remove methods within your event subscription code. In fact, the explicit declaration of an event's code can have several benefits, and is as easy to implement as a standard (non-automatic) property. Some of the added benefits include the ability to control which object is locked during adding and removing methods (the default for instance types is the instance of the class the event resides in, and for static classes, it's the type object), as well as the internal behavior of the subscriptions when the += and -= tokens are used in relationship to events. Handling the internal behavior can help to prevent duplicate subscriptions within a class.

The following is the typical implementation of events within a class:


public class NormalEventClass
{
public event EventHandler Event;

public void OnEvent()
{
EventHandler instance = Event;
if (instance != null)
instance(this, EventArgs.Empty);
}
}

public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Subscribing to normal event twice and raising event.");
NormalEventClass normalClass = new NormalEventClass();
normalClass.Event += HandleEvent;
normalClass.Event += HandleEvent;
normalClass.OnEvent();
Console.ReadLine();
}

static void HandleEvent(object sender, EventArgs e)
{
Console.WriteLine("Event Raised");
}
}

Notice that running this code causes the message "Event Raised" to appear twice on the screen. The reason for this is because the event handler is listed twice in the internal list of delegates that is called when the event is raised. This is where the trick comes in. Remember I said you can unsubscribe before subscribing to prevent duplicate event handlers from appearing in the delegate list? You could simply do this by fleshing out the declaration of your events. Let's say we use the following class instead:


public class SingleSubscriptionEventClass
{
private EventHandler _event;

private object _eventLock = new object();

public event EventHandler Event
{
add
{
lock (_eventLock) { _event -= value; _event += value; }
}
remove
{
lock (_eventLock) { _event -= value; }
}
}

public void OnEvent()
{
EventHandler instance = _event;
if (instance != null)
instance(this, EventArgs.Empty);
}
}

public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Subscribing to single-subscription event twice and raising event.");
SingleSubscriptionEventClass ssClass = new SingleSubscriptionEventClass();
ssClass.Event += HandleEvent;
ssClass.Event += HandleEvent;
ssClass.OnEvent();
Console.ReadLine();
}

static void HandleEvent(object sender, EventArgs e)
{
Console.WriteLine("Event Raised");
}
}

Now you'll notice a couple of things in the code above. First, I've declared an internal delegate of the same type as the event handler. This delegate is the invocation list that will be used when the event is raised. Second, I've declared a single object within the code that is locked when adding and removing event handlers to the event. When declaring the NormalClass, the compiler automatically locks an object when adding and removing the event handlers, but the object it locks is the instance of the object in which the event resides. It's typically better to lock a neutral object for performance reasons. Lastly, I've added the add and remove methods to the event, and in them, you'll notice, I've removed the previous event handler (if it exists) from the invocation list immediately before adding the event handler to the invocation list. Doing this ensures that each object can only subscribe to an event with a specific event handler once, and no more than once. Now, regardless of the number of times the subscription is performed, at most, only one instance of that subscriber's event handler will reside in the invocation list, thus preventing repetitive calls to the subscriber's event handler.

Monday, February 9, 2009

On Integrity and Learning C#

Yesterday I received an email from somebody who had noticed my frequent participation in online forums asking me to send him some specific code that he could use to turn in as a minor project in school. Of course, I refused. Not only did I refuse, but this student received a lengthy email lecture from me regarding the importance of learning and the purpose behind his attendance at college in the first place. There are few things that set me off more than a student asking a professional to do their school work for them, and there are several reasons for this. As this isn't the first time that something like this has happened, allow me to offer my de-facto standard response to anybody who might ask me to do their homework for them.

Here are just a few reasons why I won't answer homework questions.

  1. It's dishonest. Pure and simply, it's plagarism, cheating, and it's dishonest. There should honestly be no other reason that I should have to give here. This should be enough. It is far more important to have personal integrity than to get the perfect score in class. Your school, career, etc will change, but once you've lost integrity, it is very difficult to get it back, and only a fool goes through life believing that his lack of integrity will never be discovered.
  2. I take a great pride in what I do. I work hard. I expect those who work with me to work hard. I take offense at those who ask me to do their work for them, as it cheapens the value of my own efforts. Programming is a difficult task, and it takes hard work to do well. I've got a bookshelf of books at home that I've read in order to better my abilities, and to ask me to do your work for you is not at all respectful of the things I've personally done to strive for excellence.
  3. Eventually you will have to do your own work. In business, employers want to find people who do their work, and do it well. The success or failure of any endeavor depends on the success or failure of each of it's individuals. When an individual is simply relying on the success of his or her peers, and fails to produce his or her own success, he is bringing the entire system down and is poison to those around him.
  4. There's a great pride in doing your own work. This is true especially for programmers. There's nothing quite like finishing a beautiful piece of object oriented code and standing back and viewing it as a work of art, knowing that it's beauty is completely attributable to your own work.
  5. You are in school to learn. Put simply, you haven't been put in school to ask other people to do your work for you. The whole point of school is to struggle through figuring things out for yourself. If somebody else does your work for you, you are stealing the recognition that doesn't rightfully belong to you.
  6. There are, of course, consequences if you're found out. Yep. People get F's when their plagarism is found out. This is a pretty feeble reason to not do something, but it's still rather compelling, isn't it?
  7. I simply don't have time. Enough said for this one. I have enough to worry about without having to worry about school questions again. Been there. Done that. Got the T-Shirt. Now I'm working for a living.

Sorry for going on the rant, but I believe in education, and at some point, somebody (such as myself possibly) is going to have to rely on the quality of the work produced by those currently being educated to produce that work. Don't short-circuit that learning. Your personal integrity is far more important than getting the perfect score.

That being said, I will help at times. What is the difference between helping and cheating? If I am aware that you are working on your homework, and you post a block of code you've developed so far, but you've hit some snag somewhere, I might pose a series of questions intended to get you to think through why something might not be working, but those questions are intended to teach the mindset of programming, as opposed to simply giving the answer. In other words, I would strive to teach and not answer.

It is the job of the programmer to program. It is the job of the student to learn. Do your job. Work hard. If you need a little nudge to get you over the hump, let me know.