Snapshots in a Snap
August 6, 2014Greater Productivity with Visual Studio 2012
August 7, 2014Take advantage of even more C# code samples on MSDN and around the Web
In Synergy/DE 9.5 we introduced Synergy DBL Integration for Visual Studio, which included an experimental code converter that generated Synergy DBL code from snippets of C# code. It was rudimentary at the time and was very particular about what it would and would not convert, but it was helpful enough that we included it in the release.
Since then, the C# to Synergy DBL Code Converter has gone through a few iterations and has grown into a tool that can make MSDN and other .NET language resource sites significantly more useful and relevant when writing Synergy .NET code. Now you can take almost any C# code sample from a web resource, paste the code into the converter, and get working Synergy DBL code. However, there are still some limitations, which we ran into when preparing for this year’s Synergy DevPartner Conference. These limitations compelled us to develop yet another powerful tool, a solution converter. This article describes why we needed it and walks you through using it with a sample Microsoft solution.
The converter works best when it’s able to resolve all symbols used in the C# code. If the C# code contains a series of imports, the converter is able to resolve the types from those imports only if the associated assemblies are loaded in the current workspace. But because the converter only runs when a Synergy project is in the open solution, it has access only to assemblies in the Synergy solution rather than the project that the C# code is from. This presents a problem, for example, if you want to convert C# WPF code samples while a WinForms project is open, or vice versa. Worse still is when you want to convert C# code from a complete sample project; the locally defined types from the sample project are unavailable to the code converter, so most likely it will mistakenly assume that value types are object types.
We encountered this problem while assembling some samples for this year’s Synergy DevPartner Conference. To demonstrate the stability and capabilities of Synergy .NET, one of our senior PSG consultants, Steve Ives, picked one of the biggest, most complex best practice samples for WPF that Microsoft has made available. He chose Family.Show, which is an application for creating, manipulating, and rendering an interactive family tree. In the process of converting Family.Show from C# to Synergy DBL, we encountered numerous problems with local type resolution. Since the code had so many internal types and dependencies, the code converter output was almost completely unusable. Every file we converted needed significant touch-up, and the time spent on this was getting longer as the complexity of the files grew.
There had to be a better way. What the code converter really needed was to be able to load the type information from all of the C# files and their dependencies at the same time. From that notion, the C# to Synergy DBL Solution Converter was created. The solution converter may actually be a step beyond what was necessary to produce a functional version of Family.Show, but it seemed like an excellent opportunity to provide our customers with another powerful development tool.
The solution converter works in a fairly straightforward way. After opening the solution converter (Tools > C# to Synergy DBL Solution Converter), select an existing C# solution and an output directory. At this point, the solution converter actually builds the C# solution. If the build is successful, you can convert the solution by selecting File > Convert Solution. Output assemblies and executable files are loaded for type information, and the converter proceeds to iterate over the projects in the source solution to copy non-source files (resources, XAML files, etc.) to the output directory. With complete type information at hand, the converter then iterates over the C# source files to produce the output Synergy DBL source files. All non-C# projects and sources are copied to the output directory.
The result is a fairly accurate reproduction of the original solution, with Synergy projects in place of the C# projects. Under many circumstances, the new solution will even build and run in place of the application for the C# solution. That is not, however, a guarantee that the solution converter will produce flawless Synergy DBL code and projects. There are still subtle feature differences between the languages even though both are CLS compliant. For example, ternary conditional expressions in C# are converted into fairly accurate IF statements, and there are plenty of challenges handling C#’s case sensitivity when moving to the case-insensitive world of Synergy DBL.
Family.Show turned out to be an excellent test case for the solution converter. It combines different types of projects, plenty of resource files, complex C# code, and a few interesting hacks to produce a fully functional “best practice” demo. With the initial version of the new solution converter, it took us several weeks to convert Family.Show and get it fully functional for its premiere at the Synergy DevPartner Conference. However, by the time the solution converter was put to bed for version 10.1, it was able to convert the Family.Show solution with only a handful of compiler errors followed by a few errors at runtime, and these were all fairly easy to fix.
Walkthrough: Converting Family.Show
As an introduction to the C# to Synergy DBL Solution Converter and the types of problems you might have to solve when converting a project, the following is a start-to-finish walkthrough of the conversion process using Family.Show. Note that this walkthrough assumes you have Synergy/DE 10.1.1a, which includes some fixes in this area.
1. Download code
The first step is to get the latest copy of Family.Show from Microsoft’s open source repository. Visit http://familyshow.codeplex.com/ to download the most recent files. For the purpose of this walkthrough, we’ll use the 3.0 version from the zip file. Make sure to remove the read-only flag from the files after you have unzipped them.
2. Convert solution
Next, open the solution in Visual Studio 2010 or 2012. Since Family.Show is from Visual Studio 2008, you will most likely need to run through the version update conversion. It should be nearly seamless for this solution.
3. Clean up
The Family.Show solution has two projects: FamilyShow and FamilyShowLib. You’ll need to make a couple of changes to each of them to make the conversion process go more smoothly. Open the project properties for each, and change the target framework to .NET Framework 4.0. This will help ensure that the assembly references in the projects do not get mixed up.
In the Solution Explorer, expand the References folder in the FamilyShowLib project. Three of the references will not be correctly updated to the 4.0 framework. Remove the three references displaying the warning, and then add them back. Also add a reference to System.Xaml to ensure a clean build.
There is one more rogue reference to the 3.0 framework in the FamilyShow project. Right-click on FamilyShow in the Solution Explorer and select Unload Project. Right-click on FamilyShow again and select Edit FamilyShow.csproj. Look in the top property group for a line like this:
<MinFrameworkVersionRequired>3.0</MinFrameworkVersionRequired>
Change it to this:
<MinFrameworkVersionRequired>4.0</MinFrameworkVersionRequired>
Now, right-click on FamilyShow and select Reload Project. With these steps completed, you should be able to build and launch your C# copy of Family.Show.
4. Generate a Synergy solution
The next step is to convert Family.Show to Synergy DBL. From the Tools menu, select C# to DBL Solution Converter. In the solution converter, click the Open Solution button (or select this option from the File menu), and select the Family.Show solution. The converter builds the C# solution when it is opened. If the build fails, you will not be able to convert the solution. To load all type information, the solution converter must be able to build the solution.
Next, choose a location for the generated Synergy solution. Enter a path in the “Output folder” field or use the drilldown button for that field. Finally, click the Convert Solution button (an icon with a blue arrow) or press F5 to start the conversion. After a short time, a message should pop up stating that “The solution was successfully converted.”
The solution converter has been designed to be a straightforward tool without extra options or fluff. The solution produced by the converter will use the same unique identifiers (GUIDS) for the projects as the original solution, so you can mix and match the projects as necessary. Only a few properties will differ between C# and Synergy projects. Most of the differences will be in the source files.
Open the freshly converted solution from the output directory. It should look very much like the C# solution, except now all source files will have the .dbl extension and will contain Synergy DBL source code.
5. Build the Synergy solution
With a set of Synergy projects on hand, the next steps are to build, debug, and run the Synergy version of Family.Show. Fortunately, there will be only a few bugs in the source code. Select Build > Build Solution and start debugging.
Most of the issues are simple for a developer to fix but surprisingly difficult for the converter to get right:
%DBL-E-BSTMTCH:
%DBL-E-TYPMISMCH:
Since Synergy DBL does not have ternary conditional statements, the converter does its best to split the conditional into a standard IF statement. A ternary conditional returns a value, so the converter needs a temporary variable of that type in order to store the value for use in its original code line. When the converter cannot figure out the value, it uses type @Object. If the error line states that a mismatch or best match between a type and @Object occurred, the converter probably made a mistake on the generated_conditional variable declaration. Use the type mentioned in the error message to determine the correct type for the generated_conditional variable.
%DBL-E-TYPMISMCH, Type mismatch between @System.Predicate<Object>:
Similar to the previous error, the converter often has problems determining a correct type argument when the return type for a ternary conditional requires one. In this case, affix the correct type argument to the generated_conditional variable declaration.
%DBL-E-IMPOUTNS:
The original C# project allows for IMPORT statements inside namespace declarations. Synergy DBL, however, does not. The easiest solution is to move the IMPORT to the top of the file.
%DBL-E-INVPROGENT, Invalid program entry:\
A logical statement in C# can span multiple lines and contain comments. Synergy DBL is a bit different, and for this reason, a particular block of code did not translate well. The comments in this section can be moved above the attribute or deleted. The attribute then needs continuation characters, or it needs to be on one line.
%DBL-E-INVSTMT:
In this particular block of code, the compiler can’t determine if “start” is the statement or a variable within the scope. The easiest way to fix an ambiguous symbol is to fully qualify it. The statement should be referencing “this.start” rather than just “start”.
%DBL-E-ISSTAT, Class type required to access static member:
The compiler believes that the local variable “brush” is referring to the type called “Brush”. Synergy is not case sensitive, so there are many code snippets and variable names that may not convert cleanly from C#. To solve this issue, rename the local variable wherever it is used in order to limit the ambiguity. Note that there is an actual reference to the type “Brush” in this scope where a static property is being accessed: “Brush.OpacityProperty”.
%DBL-E-NOOPER, No operator op_Addition:
C# includes syntactic sugar for concatenating most types with a string. This is achieved by implicitly calling the associated ToString() method for the non-string type. Synergy does not offer this feature. As a result, the code converter attempts to detect concatenation with strings in order to insert an explicit ToString() call. The converter does not, however, recognize the string concatenation when combined with an equals operator. The type on the left side of this expression is an object. Since it is the variable or property that will receive the value, the expression needs a little editing, for example:
<align=center> VersionLabel.Content = VersionLabel.Content.ToString() +
& string.Format(CultureInfo.CurrentCulture, “{0}.{1}.{2}”, local_version.Major,
& local_version.Minor, local_version.Build)
%DBL-E-NOOPER, No operator op_GreaterThan(System.Int32, D):
There is a grey area with comparison operators between literals and the result of an enum bitwise operation. C# does some special processing to match the 0 literal against the result of the bitwise operation, but if the 0 were to be replaced with a variable of type int, the C# code would fail. Synergy requires the code to be more explicit. Cast the result of the bitwise operation to type int to resolve this problem:
<align=center> ((int)(Keyboard.Modifiers & ModifierKeys.Control) > 0)
6. Debug the Synergy solution
The next step is to build and run the solution. Running the solution, however, does not quite produce the desired result. You will see runtime issues, which leads us to debugging these issues. This can be the biggest time sink in the solution-conversion process. For example, if the debugger cannot even place you into executable code, you know there is a serious problem with the solution, but you won’t get much context information. The key is to read the information that is provided. Fortunately, the Family.Show conversion results in a common (and irritating) error that illustrates this:
XamlParseException indicates that the runtime that handles loading and running the XAML elements has encountered a problem. The first step in solving the problem is to get more information.
1. Click “View Detail…” to get more information about the exception. In this window, the inner details of the XamlParseException object are visible. The BaseUri property indicates that the failing file was “{pack://application:,,,/FamilyShow;component/App.xaml}”. The App.xaml file is fairly straightforward; it specifies a startup URI of MainWindow.xaml and defines the BlackResources.xaml file as a resource dictionary.
2. Examine the InnerException property for more information.
{“Cannot locate resource ‘skins/black/blackresources.xaml’.”}
This is a more obvious problem. If the resource loader cannot find the file specified in App.xaml, then the file must not be in the right place, or the resource might not be configured correctly in the project. Checking the /bin/Debug/Skins/Black/ directory shows that the file exists in the correct place.
Despite the fact that Family.Show is a best practice application, it is a little lax when it comes to adhering to all of Microsoft’s standards. According to the MSDN*, the path to the resource file in App.xaml should be specified a little differently:
pack://siteoforigin:,,,/skins/black/blackresources.xaml
Stop debugging, change the value, rebuild the solution, and run it once more. If all goes well, Family.Show runs up and awaits selection of an existing family tree or the start of a new one.
While converting an existing solution is not exactly an everyday occurrence, it can prove very useful as a learning tool. By completing this walkthrough, you will have quickly and easily generated a code base to use as reference material for .NET programming. Family.Show demonstrates WPF, IO, and serialization in .NET, just to name a few features, which can now be put straight into practice in Synergy .NET applications.
With the ability to convert almost any C# sample solution available on the web, Synergy developers have more resources to expand applications and deliver a better customer experience than ever before.