February 2009 - Posts

I was reading what was new for Visual Basic 10 over on the VB Futures site, when I came across the following statement:

Overall Visual Basic 10.0 and C# 4.0 will have the closest feature parity at any point in the history of the languages, which will greatly benefit .NET developers who do work in both.

This statement refers to the language changes coming in Visual Studio 2010, such as Visual Basic getting some C#-like features, such as multiline lambdas, auto-implemented properties and implicit line continuation, and C# getting some Visual Basic-like features, such as late binding, implicit pass-by-ref and optional parameters.

I’m disappointment that the language teams feel the need to have what they call ‘co-evolution’, where any new features in one language also get added to the other. Is there any point Microsoft investing in two separate languages, if they do exactly the same thing?

In my opinion (which does not represent Microsoft’s), we would better off adding C-style macros to one of the languages, allowing us to #define the syntax differences between the two languages, and then kill off the other.

What do others think? Should Microsoft continue to support two (what are) basically the same languages, or should they attempt to differentiate them like they have done with F#?

I ran across something interesting on an internal alias about a new marketing campaign on the Visual Studio Team System marketing site that allows you to customize an amusing video that you can send to friends and team members. What caught my eye wasn’t the video itself, but the error that some users were encountering when attempting to view one of the Silverlight-based videos:

Message: Unhandled Error in Silverlight 2 Application [Format_InvalidString]
Arguments:

Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=2.0.31005.0&File=mscorlib.dll&Key=Format_InvalidString   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseDouble(String value, NumberStyles options, NumberFormatInfo numfmt)
   at System.Double.Parse(String s, NumberStyles style, NumberFormatInfo info)
   at System.Double.Parse(String s, IFormatProvider provider)
   at System.Convert.ToDouble(String value)
   at PepTalk_Full.DataObjects.doTextOverlay..ctor(XElement element)
   at PepTalk_Full.DataObjects.doPepTalk.Init()
   at PepTalk_Full.DataObjects.doPepTalk..ctor()
   at PepTalk_Full.App.wc_DownloadStringCompleted(Object sender, DownloadStringCompletedEventArgs e)
   at System.Net.WebClient.OnDownloadStringCompleted(DownloadStringCompletedEventArgs e)
   at System.Net.WebClient.DownloadStringOperationCompleted(Object arg)

To keep download sizes smaller, the client Silverlight plug-in does not contain Exception error messages, but by clicking the URL above, or by looking at the stack can you guess what the problem is? I’ll give you a hint – Convert.ToDouble(String) passes CultureInfo.CurrentCulture as the IFormatProvider argument to Double.Parse.

Yep, you guessed it, basically, the application is attempting to parse a string that it has downloaded from the web and the call to Convert.ToDouble is failing because it is expecting the format of the string to match the current culture, while the string itself is formatted using another culture. For example, the string likely contains a value formatted using the invariant culture, say ‘1.00’, but when a visitor from Germany or Norway comes to visit, Convert.ToDouble(String) is looking for a string in the format ‘1,00’.

The irony in all this is that if the Microsoft team or contractor that wrote the Silverlight application were actually using the Code Analysis feature of Team System, they would have received the following warning from Specify IFormatProvider:

Because the behavior of 'Convert.ToDouble(string)' could vary based on the current user's locale settings, replace this call in 'doTextOverlay.doTextOverlay(XElement)' with a call to 'Convert.ToDouble(string, IFormatProvider)'. If the result of 'Convert.ToDouble(string, IFormatProvider)' will be displayed to the user, specify 'CultureInfo.CurrentCulture' as the 'IFormatProvider' parameter. Otherwise, if the result will be stored and accessed by software, such as when it is persisted to disk or to a database, specify 'CultureInfo.InvariantCulture'.

All the developer has to do is to call the overload of Convert.ToDouble that takes an IFormatProvider passing it CultureInfo.InvariantCulture and the application would work on all systems regardless of the user’s culture.

The moral of the story is, use the tools available at your disposal – if you have Team System, use Code Analysis, otherwise, we still offer FxCop as a free download – they both catch bugs like this one.

Posted by David Kean | 2 comment(s)
Filed under: ,

I’m speaking at Code Camp Oz 2009 on April 4th in Wagga Wagga, Australia. I’ll be giving a talk called ‘A lap around the Managed Extensibility Framework’, in which I’ll give a run through of the major features of MEF.

Mitch Denny has also announced the rest of the speakers & sessions, which looks like a great line up this year. I had the pleasure of attending the first one in 2005 when I was last in Australia and it’s not only a great (and free) way to learn more about current and new technologies, but is also a great place to network with peers.

It’s free and run over the weekend of April 4th/5th. Sign up today.

Posted by David Kean | with no comments
Filed under:

One of the things that you might run across when starting to work with MEF, is that by default, all parts are created as singleton (‘shared’) instances.

For example, given the following part:

[Export]
public class MyView
{
}

Running the following code:

TypeCatalog catalog = new TypeCatalog(typeof(MyView));
CompositionContainer container = new CompositionContainer(catalog);

var view1 = container.GetExportedObject<MyView>();
var view2 = container.GetExportedObject<MyView>();

Console.WriteLine("Are same object? " + (view1 == view2));

Outputs:

Are same object? True

In certain scenarios, such as web applications, you typically want the reverse, that is, a new instance (‘non-shared’) of a part created on every request.

We allow you to indicate that, using the CompositionOptionsAttribute:

[Export]
[CompositionOptions(CreationPolicy=CreationPolicy.NonShared)]
public class MyView
{
}

Unfortunately, if you have a lot of them, this can be a bit of a hassle to do this for every part. As luck would have it, the latest drop of MEF allows you modify the default with a little bit of code:

public class TransientCompositionContainer : CompositionContainer
{
    public TransientCompositionContainer(ComposablePartCatalog catalog)
        : base(catalog)
    {
    }

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition)
    {
        definition = AdaptDefinition(definition);
        
        return base.GetExportsCore(definition);
    }

    private ImportDefinition AdaptDefinition(ImportDefinition definition)
    {
        ContractBasedImportDefinition namedDefinition = definition as ContractBasedImportDefinition;
        if (namedDefinition != null && namedDefinition.RequiredCreationPolicy == CreationPolicy.Any)
        {   // Only change the creation policy if the importer/requester did not specify one
 
            definition = new ContractBasedImportDefinition(namedDefinition.ContractName,
                                                           namedDefinition.RequiredMetadata,
                                                           namedDefinition.Cardinality,
                                                           namedDefinition.IsRecomposable,
                                                           namedDefinition.IsPrerequisite,
                                                           CreationPolicy.NonShared);
        }

        return definition;
    }
}

Basically what is happening above is that all requests to the container are routed through GetExportsCore. When we see a request (represented as an ImportDefinition) that states that it does not have a preference for a particular creation policy (which is the default when querying from the container, or when using the [Import] attribute), we create a new request that explicitly specifies that it wants a non-shared instance and route that back to the base.

Running the above sample, substituting the standard container with the transient container, should now output:

Are same object? False

There we have it – a container that defaults to non-shared parts. You can download the container below.

Posted by David Kean | 1 comment(s)
Filed under: