Bugs, Workarounds, And Gotchas in VS 2008
Kathleen discovers a bug in the Visual Basic 9.0 compiler. Also, resolving recursion problems; binding properties in the Workflow designer; some guidelines on using extension methods; moving to .NET 3.5, and more.
Technologies mentioned in this article include VB.NET, C#, and XML.
I discovered a serious bug in the Visual Basic 9.0 compiler shortly before Visual Studio 2008 was released. The symptom is that certain lines of code are not included in the IL output. Like all programmers, I expect the source code I write to be reflected perfectly in the applications I create and I depend on this fidelity.
I discovered the problem after upgrading to 2008. My code didn't do what I expected and when I placed a breakpoint, the breakpoint moved. Exploring this via Reflector, I discovered the call missing in the IL. I zipped the solution for the Visual Basic team. After hard work and long hours, they have an explanation, a short-term mitigation strategy, and a fix planned for the first 2008 service pack.
Until the service pack is released, you'll want to know whether this bug might affect you. If you have less than five projects in your solution, or you are not using generics with constraints (see "Utilize Constraints in Custom Generic Classes," August 2007) you will not encounter this bug. If you have four projects, they need to be in a fairly specific arrangement called a diamond reference. I created this scenario with an assembly called GenericBase that has generics with interface constraints (see Figure 1). These interfaces are in a separate assembly called Common. The business objects are in a third assembly called BizObject and these three assemblies are referenced by a Windows Form application. Finally, a Test project resides in the solution as a second "root." The VB compiler becomes confused because the code behind the mix of file and assembly references can become out of sync. BizObject is a C# assembly and references from VB assemblies to C# are effectively file references, but it could also occur if BizObject was a VB assembly and had a file reference.
This bug will not affect many people but is extremely serious when it occurs. Neglecting to call key code could cause your app to behave badly. This issue brought to light how tedious it is to check whether you are using file or assembly references--open the project in a text editor and discover the reference types yourself. The Visual Basic team is working on a mitigation tool to recognize the issue and offer to update your references. You'll find links to this tool and more information in my blog.
Q Visual Studio is crashing when I compile an application that contains a particular workflow that relies on a set of custom activities. I start the compile and almost immediately Visual Studio shuts down with a message that it's encountered a problem and must close. I've reproduced the problem with this specific workflow on two machines. Both machines run other workflows without any issues. I'm using Visual Studio 2008. Can you figure out what's going on?
A This is a tricky problem, so it's a great time to point out that you can submit and track bugs to the Microsoft teams through a tool called Connect that you can access through the Community/Send Feedback menu option in Visual Studio 2005 or Help/Report a Bug in 2008. If you encounter a bizarre bug, try to capture as much information as possible, including zipping the offending source code (in case the problem mysteriously resolves itself) or taking a screenshot that illustrates the issue.
This particular problem is because of illegal nesting of your classes. Activity B derives from Activity A, and Activity A also contains an instance of Activity B (see Figure 2). This sends the compiler into a recursive death spiral and takes Visual Studio down with it. You can cause a similar meltdown if Activity A contains Activity B and Activity B contains Activity A. Remove the circularity and you're back in business. You can create this problem in VB or C#, although VB crashes on the compile and C# crashes when using the broken user control or activity. You'll see similar results with illegal nesting in WinForms, and it occurs in VS 2005 and VS 2008.
The unfortunate thing about this problem is that Visual Studio doesn't supply a message. The folks at Microsoft may find a solution for a future version of Visual Studio. But for now, if Visual Studio crashes on compile, or when you place a particular activity or user control onto a design surface, check your application manually for illegal nesting.
Q I'm trying to bind a Boolean property in the Windows Workflow designer for 2008. When I try to set the binding, I just get true and false in a combo box, and don't get the button that allows me to set the binding. Can you tell me how to bind the properties?
A The Workflow designer is a bit tricky when binding non-string properties. While string has an ellipses button that takes you to the binding dialog, other types use a combo box to select values and don't have the ellipses button.
There are two solutions. One of the commands at the bottom of the property dialog is "Bind Selected Property," which takes you to the binding dialog. This command isn't always enabled, but I've had good luck enabling it by changing the value in the combo box. Some property types, such as streams, don't allow this approach. Bindable properties also have a small yellow icon. This icon doesn't look like a button, doesn't provide any mouse feedback, and doesn't respond to a single click, but it does bring up the binding dialog if you double click on it. Depending on your screen resolution, this can take moderate dexterity, and there's no keyboard shortcut.
Q Can you comment something out within an XML literal? I have a long XML literal and I want to remove parts of it for testing.
A XML literals in Visual Basic output their content as-is. You can't comment out sections
Q My workflow was working and suddenly I have dozens of errors. Some of them don't make much sense, while some lack line numbers. I'm sure I've made dumb mistakes; I just don't know how to find them. I have six assemblies. How can I resolve all these errors?
A The VS 2008 workflow compiler gives better errors than the 2005 version. However, it still can give a blizzard of secondary errors that obscure the primary errors. Begin by learning the dependency order of your build because most errors result from the compiler being unable to find required assemblies because they failed to build. Start with assemblies that don't have any dependencies and ensure they build. Then look for issues in the assemblies that depend only on assemblies that build successfully. Working outward in this way will generally uncover the problem. Also, primary problems generally have line numbers.
One of the ways you can create compiler errors in workflows is to use rename refactoring in VB or C#. This doesn't change names where they appear in strings, which is common with the dependency properties and workflow binding. In workflow, consider changing names through search and replace, or at least doing a search following a rename refactor.
Q Can you replace a handles clause with a lambda expression to create a closure on a value in the local routine that sets the handles clause?
AddHandler barItem.ItemClick, _
A No, Visual Basic 9.0 supports only lambda expressions, and you cannot use them where the required delegate signature is a Sub.
Q I've upgraded my project to Visual Studio 2008 and tried to use the Extension attribute. But I get a compiler error indicating that VS 2008 can't find the extension attribute, even though I have it fully qualified with the namespace I copied from help. Can you tell me what's wrong?
A The upgrade process that you run when you move your C# or VB project into Visual Studio 2008 doesn't alter your references. You need to reference System.Core.dll to use extension methods.
I'm guessing that you're in Visual Basic because C# uses the "this" keyword before the parameter (for more details see C# Corner, "Exploring C# 3.0") and gives the helpful error message: "Cannot use ‘this' modifier on first parameter of method declaration without a reference to System.Core.dll. Add a reference to System.Core.dll or remove ‘this' modifier from the method declaration."
Visual Basic uses the Extension attribute directly and gives the missing type error: "Type ‘System.Runtime.CompilerServices.Extension' is not defined." You need to both upgrade the project to VS 2008 and reference System.Core.dll to use extension methods.
Q My organization is having some spirited debates on how to use extension methods. Some groups want to use them extensively, others want to avoid them, and still other groups want to use them only for a handful of things. How can we resolve this and move on?
A Extension methods will be valuable to your projects because they guide programmers to the right utility methods and simplify reading code. They're very valuable, but you can abuse them by creating too many and polluting IntelliSense, failing to follow framework naming and design guidelines, or creating inconsistencies within your organization. See a list of these guidelines in "Keeping Your Extension Methods Under Control."
I see fewer than a dozen good candidates for string extensions, including SubstringBefore, SubstringAfter, SubstringBeforeLast, SubstringAfterLast, Replace (case-insensitive overload), EqualsIgnoreCase, and IsNullOrEmptyValue. There are a few good candidates for extension methods for XML and data (adding parameters, for example), and a few classes such as System.Collections.ObjectModel.Collection that need a set of features.
In general, you won't write extension methods for your own classes because you can modify the class. However, you can use extensions to filter functionally used by programmers in different environments.
Extension methods appear almost as though they're part of the class, so use normal helper methods to solve local problems rather than extension methods. You won't create many, but review your utility methods to discover which ones to change to extension methods. Extension methods are a tremendous asset to your development, unless you use them excessively or abuse them with inconsistency.
Q My manager hates inferred typing. He says it will create object variables. What do you think about it?
A Inferred typing lets you leave off the type on a variable declaration:
Dim x = 3
var y1 = 2;
This does not create an object variable except in Visual Basic with Option Strict turned Off (not recommended). In Visual Basic, if Option Strict is On and Option Infer is Off, this code throws a compiler error. If Option Infer is On in VB and always in C# this creates a strongly typed variable. The compiler gives you an error if you assign the wrong type; it's just going a step further and setting the type it already understands.
It took some time for me to appreciate inferred typing. I thought there would be less information available when I read the code. But as I've gotten used to it, I find that I use inferred typing only for a handful of types including string, date, and integer literals. I don't find it useful in declaring new instances of native types in VB because it's only one character longer to type the A's. However, it's nice for creating new instances in C#. I also like it for casting. It feels dumb to create a variable of a type only to cast immediately to that variable--the type appears twice on one line. Once I became accustomed to them, I liked not having to declare variable types; it's one less thing to remember.
The good news is that you're in VB, so you can turn off inferred typing, except in files that have certain Language Integrated Query expressions. If your team hates them, you can turn them off at the project level and then turn them back on if you need them in specific files. Inferred typing, like extension methods and partial classes, is a compiler trick, so you can't write FxCop rules to ferret out usage your team doesn't consider correct. That's because FxCop rules run against the IL, not the source code.
Q When do you think we should move to .NET 3.5?
A .NET 3.5 is an awesome release. I've covered issues with .NET 3.5 and Visual Studio 2008 to help you avoid a few pitfalls on the transition. But, I think its features will improve your code more than any other .NET release. Depending on your organization's capacity for change, you should probably move within the next three to six months. This should be a painless change for most projects and offers a range of new features to improve your code.