July 9, 2008

CodeRush with Refactor! Pro vs ReSharper

Filed under: Tools

Every developer knows already, that Visual Studio is not sufficient enough for code writing. There are lots of Add-ons which are able to improve daily work to significant manner. I use such tools everyday as : ViEmu, GhostDoc and Smart Paster. I used also CodeRush + Refactor! Pro from 1.5 year, but from moment of appearance of ReSharper 4.0 public beta versions, I decided to take closer look to this tool.

After several months of using ReSharper, I’ll try to make a small comparison of both products functions in range I used most often.

Some images are linked with external animations.

Refactoring

Both tool contain similar amount and quality of refactoring functionality.  There is a small inconvenience of mouse using during refactoring in ReSharper. Just keyboard usage is enough for CodeRush using.

Here is simple example of method signature change

R#

 

CR

Code generation

Both tools have sound and weak parts in code generation. Better possibilities of creating more intelligent code templates are in CodeRush than on ReSharper. It’s all about definition of conditions when and which template can be generated. In CodeRush, you can define that writing ‘c’ and then ’space’ pressing will generate "case" keyword in "switch" statement but in "foreach" loop it will generate "continue" keyword. ReSharper is less flexible in defining such conditions. In fact, I can live without it. The bigger problem is that CodeRush cannot allow you to hare these templates among other users. Templates are kept in user local folders and there is only export and import function. ReSharper can share templates in many ways:

  • per system
  • per user
  • per solution
  • per personal solution
  • defined in external file - it helps to maintain corporate range templates

ReSharper has one more kind of template, which CodeRush does no have it at all, file template.

We can treat unit tests as a API sketch, as as draft for defining how our class can be used. To do that we just write name of methods and proprieties which actually doesn’t exist yet. Both tools will generate proper stubs for them.

ReSharper isn’t sometimes as intuitive as it would be. That’s why I suggest to take a simple  look to documentation before using it, if you don’t want to be surprised. Some day I wanted to create some overloads for a method. In CodeRush, you can place cursor on method name, press Ctrl + `, and you will see how easy is to create overloads by using "space" and "left, right arrows"…

… in ReSharper you need to select method parameters and then press Alt+Enter …

In that situation you cannot make and overload  for example removing first and third method parameter.

Generating additional code based on existing code is solved in two ways. Example of generating properties based on existing fields.In ReSharper, you need to press Alt + Insert and then choose fields …

CodeRush has SmartPaste i SmartCopy. In that case it is enough to copy field and paste it. That’s what developers love the most ;) copy & paste :).

This way is not good enough if we have a bunch of fields which are not grouped together and are different types. In that situation SmartPaste doesn’t work too good, ReSharper’s way doesn’t look nicer but work better.

Additional ReSharper functionalists …

… which there is lack of in CodeRush.

Code analysis

ReSharper analyses code all the time and can point out errors even before compiler will do that. Additionally suggest us how to better write a code.

But it has price. This functionality needs more memory from our machine and can slow down Visual Studio when you are writing code in DSL-like manner. Many methods or properties connected in one logical line like in NBehave testing.

More about code analysis

Code reordering and formatting

Java users had a Jalopy, C# users had nothing until ReShareper came out. In my opinion it is the best tool for automatically C# code formatting in the market. It is fully configurable and configuration can be shared among other developers. This will allow us to make our own corporate standard of code formatting.

More about code reordering and formatting

ToDo Explorer

Visual Studio allows us to insert special tags in comment such us TODO, FIX ,HACK and so on. But it cannot make a summary list of them from whole solutions. ReSharper can do that.

Unit Testing

Now we have all in one place. Running, debugging and profiling tests also. ReSharper ca run NUnit test only by default. But there is some plug-ins which integrate TestRunner with other frameworks.

kick it on DotNetKicks.com

June 22, 2008

ReflectionHelper - DSL-like reflection manipulating

Filed under: .NET, C#, rod.Commons

I’ve added ReflectionHelper and ReflectionHelperExtensions classes in rod.Commons project. These classes are useful for simple object modifying by reflection.

ReflectionHelper is for NET 2.0 and above and can be used like this:

   1: public void ChangeTransferAmountToTenDollars(Transfer transfer)
   2: {
   3:     return ReflectionHelper.For(transfer)
   4:         .Field("amount")
   5:         .SetValue(10)
   6:         .Property("Currency")
   7:         .SetValue("USD")
   8:         .Return<Transfer>();
   9: }

ReflectionHelperExtensions is for NET 3.5+ and it is just extension adding Reflect() method for easier using ReflectionHelper like this:

   1: public void ChangeTransferAmountToTenDollars(Transfer transfer)
   2: {
   3:     return transfer.Reflect()
   4:         .Field("amount")
   5:         .SetValue(10)
   6:         .Property("Currency")
   7:         .SetValue("USD")
   8:         .Return<Transfer>();
   9: }

kick it on DotNetKicks.com

rod.Commons - Goes public

Filed under: .NET, C#, rod.Commons

Every developer has his own utility library where collects very useful classes. I decided to share my pack of tricky tools which are named "rod.Commons". I’m currently doing some refactoring and code cleaning to make it more readable so you will find not much code there yet. rod.Commons is available in Google Code - http://code.google.com/p/rodcommons/. I hope that some of you will find it useful and I will be appreciated for any comments and ideas.

February 21, 2008

Compiling solution in Visual Studio with generating project version based on SVN revision

Filed under: C#, Subversion, MSBuild

I’ve used to compile projects with NAnt. I’m using MSBuild currently. Main reason was to unify  build scripts during projects building inside and outside of Visual Studio. NAnt was helping me to create dynamically AssemblyInfo and than to compile into project. Attributes such as AssemblyTitle or AssemblyCompany were managed from one place and project version was generated with SVN revision based on. AssemblyInfo file wasn’t included into the project that’s why Solution Explorer didn’t even know about its existence. There was no problem with building project and messages about missing AssemblyInfo file despite of absence of this file in SVN repository. Now it is time MSBuild do this same for me :).

Let’s start with example of file compiling which is absent in Solution Explorer. Just add new AssemblyInfo.cs and then make it "Exclude From Project". Now we need to add it dynamicaly to the list of compiled files. Let’s modify our actual project file - .csproj, find target named "BeforeBuild" and put there some lines …

   1: <Target Name="BeforeBuild">
   2:     <CreateItem Include="AssemblyInfo.cs" Condition="Exists(’AssemblyInfo.cs’)">
   3:         <Output ItemName="Compile" TaskParameter="Include"/>
   4:     </CreateItem>
   5: </Target>

As you probably noticed AssemblyInfo.cs has been compiled with our project although it is not visible in Solution Explorer.

It will be good if all our projects in solution will have generated such information in the same manner. Let’s do some refactoring of our project file and make external helper file, which I usually call "Common.proj". Make "Common.proj" looks like this …

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
   3:     
   4:     <!– AssemblyInfo Properties –>
   5:     <PropertyGroup>
   6:         <AssemblyInfoFile>AssemblyInfo.cs</AssemblyInfoFile>
   7:     </PropertyGroup>
   8:     
   9:     <!– Add additional depends to Build target –>
  10:     <PropertyGroup>
  11:         <BuildDependsOn>
  12:             IncludeGeneratedAssemblyInfo;
  13:             $(BuildDependsOn)
  14:         </BuildDependsOn>
  15:     </PropertyGroup>
  16:     
  17:     <Target Name="IncludeGeneratedAssemblyInfo">
  18:         <CreateItem Include="$(AssemblyInfoFile)" Condition="Exists(’$(AssemblyInfoFile)’)">
  19:             <Output ItemName="Compile" TaskParameter="Include"/>
  20:         </CreateItem>
  21:     </Target>
  22: </Project>

We used property "BuildDependsOn" in lines (10-15), which is used by "Build" target and contains list of depended  targets. Now we don’t need to modify "BeforeBuild" target in .csproj file it will be enough to include "Common.proj" in .csproj file. You can read more about "BuildDependsOn" in - How To: Add Custom Process at Specific Points During Build (Method #2)

Let’s edit beginning of our project file .csproj like this …

   1: <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
   2:     <PropertyGroup>
   3:         <RootPath Condition=" ‘$(RootPath)’ == ‘’ ">$(MSBuildProjectDirectory)..\..\..\..\</RootPath>
   4:     </PropertyGroup>
   5:     <PropertyGroup>
   6:         <Configuration Condition=" ‘$(Configuration)’ == ‘’ ">Debug</Configuration>
   7: … cut …

"RootPath" property defined in line (3) is a helper property which points out on folder root of our solution tree where "Common.proj" and other helper files are located. As I mentioned earlier we don’t need to modify "BeforeBuild" so part of .cproj file will look like this …

   1: … cut …
   2: <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   3: <Import Project="$(RootPath)\Common.proj" />
   4: <!– To modify your build process, add your task inside one of the targets below and uncomment it. 
   5:      Other similar extension points exist, see Microsoft.Common.targets.
   6: <Target Name="BeforeBuild">
   7: </Target>
   8: <Target Name="AfterBuild">
   9: </Target>
  10: –>
  11: … cut …

"Common.proj" is just included in line (3). From this time only this file is needed to modify.

We will use target "AssemblyInfo" for generating assembly info file and target "SvnInfo" to reach for actual svn’s revision number. These tasks are included in MSBuild Community Tasks.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
   3:     
   4:     <!– AssemblyInfo Properties –>
   5:     <PropertyGroup>
   6:         <AssemblyInfoFile>AssemblyInfo.cs</AssemblyInfoFile>
   7:         <AssemblyTitle>Title of my library.</AssemblyTitle>
   8:         <AssemblyDescription>My Product made by Me.</AssemblyDescription>
   9:         <AssemblyCompany>My Company Ltd.</AssemblyCompany>
  10:         <AssemblyProduct>My Product</AssemblyProduct>
  11:         <AssemblyVersion>1.0.0</AssemblyVersion>
  12:     </PropertyGroup>
  13:     
  14:     <!– Add additional depends to Build target –>
  15:     <PropertyGroup>
  16:         <BuildDependsOn>
  17:             IncludeGeneratedAssemblyInfo;
  18:             $(BuildDependsOn)
  19:         </BuildDependsOn>
  20:     </PropertyGroup>
  21:  
  22:     <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
  23:  
  24:     <Target Name="IncludeGeneratedAssemblyInfo">
  25:         
  26:         <!– Get the revision number of the local working copy –>
  27:         <SvnInfo LocalPath="$(MSBuildProjectDirectory)">
  28:             <Output TaskParameter="Revision" PropertyName="SvnRevision"/>
  29:         </SvnInfo>
  30:         
  31:         <AssemblyInfo CodeLanguage="CS"
  32:             OutputFile="$(AssemblyInfoFile)"
  33:             AssemblyTitle="$(AssemblyTitle)"
  34:             AssemblyDescription="$(AssemblyDescription)"
  35:             AssemblyCompany="$(AssemblyCompany)"
  36:             AssemblyProduct="$(AssemblyProduct)"
  37:             AssemblyVersion="$(AssemblyVersion).$(SvnRevision)"
  38:             AssemblyFileVersion="$(AssemblyVersion).$(SvnRevision)" />
  39:  
  40:         <CreateItem Include="$(AssemblyInfoFile)" Condition="Exists(’$(AssemblyInfoFile)’)">
  41:             <Output ItemName="Compile" TaskParameter="Include"/>
  42:         </CreateItem>
  43:     </Target>
  44: </Project>

.. and that’s the final version.

kick it on DotNetKicks.com

February 14, 2008

Applying ASP.NET 2.0 CSS Themes for Web Controls from DevExpress

Filed under: DevExpress, ASP.NET

I’m using DXperience v2007 vol 3 web controls from DevExpress in my project. These controls rendering is based on CSS delivered by vendor. Of course every developer can easily deliver his own CSS files for custom rendering. All is described in "How to use a sample CSS file together with the CssFilePath and CssPostfix properties" knowledge base article. I recommend to read it first before following the rest of this text.

CSS files for DevExpress controls are passed to the browser by WebResource.axd if any of controls on page has empty CSSFilePath and CSSPostfix. Here is HTML head rendered for ASP.NET’s StyleSheetTheme "WarmSky".

   1: <head>
   2:   <link rel="stylesheet" type="text/css" href="/WebResource.axd?d=0pW-VO1NI7dfSm0O0Zq2ACMk4iRYek_Z5HOc04vPAnw8rKCun3Q8F4Pym8tFdctHHl4XQbUWFljcY6QXnl3p7siLCGDJ1iKxufw0w7iv7o1SPl7T7o3UZQUTi-mf3HfnnTK_ucsD_MJr-bXTL61n0g2&amp;t=633379322277157280" />
   3:   <link rel="stylesheet" type="text/css" href="/WebResource.axd?d=0pW-VO1NI7dfSm0O0Zq2ADLPYMn7C88nFaD1LYCGrG_m7LNXR4VkbF6eCu4o_f7P_mjdqJx3sBZZrQ4bq76FtHEcj1_39ooWlWE2tPILiLqxFiQpwhIOKyztP9HejXbuTlRxa7U-fgC-XpX8zwnYmQ2&amp;t=633379322285068656" />
   4:   <link rel="stylesheet" type="text/css" href="/WebResource.axd?d=0pW-VO1NI7dfSm0O0Zq2AMHyrkIXBazF7PZQtbA9x6A1Th7TVoM38ntOqyETlkyMPdYqI3W_YqfVOkNGOxuNNsjpxsJ17m3w-X4OU9YXQdI1&amp;t=633379322298387808" />
   5:   <link href="../App_Themes/WarmSky/Styles/main.css" type="text/css" rel="stylesheet" />
   6:   <title>Some Title</title>
   7: </head>

Good solution is to prepare CSS files for DevExpress controls and put them in theme folder. Then just make sure that all DevExpress controls in page has set CSSPostfix property. Of course it is quite boring to set properties on every DevExpress control in design time. To make it more automatic let’s create simple DXControlsHelper static class and put there method which applies theme to control.

   1: /// <summary>
   2: /// Applies theme for DevExpressControl.
   3: /// </summary>
   4: /// <param name="control">The control.</param>
   5: /// <param name="themeName">Name of the theme.</param>
   6: internal static void ApplyThemeToControl(ASPxWebControl control, string themeName)
   7: {
   8:     if(control == null)
   9:         return;
  10:  
  11:     if(String.IsNullOrEmpty(themeName))
  12:     {
  13:         control.CssPostfix = null;
  14:         control.CssFilePath = null;
  15:     }
  16:     else
  17:     {
  18:         control.CssPostfix = themeName;
  19:         // control.CssFilePath = "~/App_Themes/" + themeName + "/DXControls/{0}/styles.css";
  20:     }
  21: }

This method sets only CssPostfix property because we’ve put DXControls CSS files in Theme folder so they will be automatically included during page rendering. That’s why line (19) is commented out.

Now it’s is time to deliver all DXControls from the page. To make sure that we will deliver all controls let’s make some recursive method to find all of them. To make it more universal let’s use generics.

   1: /// <summary>
   2: /// Finds recursively all controls of defined type.
   3: /// </summary>
   4: /// <typeparam name="TControlType">The type of the control type.</typeparam>
   5: /// <param name="root">The root.</param>
   6: /// <returns>List of controls.</returns>
   7: internal static IEnumerable<TControlType> FindAllControlsRecursively<TControlType>(Control root)
   8:     where TControlType : Control
   9: {
  10:     if(root == null)
  11:         yield return null;
  12:  
  13:     foreach(Control item in root.Controls)
  14:     {
  15:         if (item is TControlType)
  16:             yield return item as TControlType;
  17:         foreach (TControlType itemChild in FindAllControlsRecursively<TControlType>(item))
  18:             yield return itemChild;
  19:     }
  20: }

Now it is time to apply theme to all controls. Hmm … maybe not to all …

   1: /// <summary>
   2: /// Applies theme to all child DXControls from root.
   3: /// </summary>
   4: /// <param name="root">The root.</param>
   5: /// <param name="themeName">Name of the theme.</param>
   6: internal static void ApplyThemeToControlsRecursively(Control root, string themeName)
   7: {
   8:     foreach (ASPxWebControl item in FindAllControlsRecursively<ASPxWebControl>(root))
   9:     {
  10:         if(String.IsNullOrEmpty(item.CssPostfix) && String.IsNullOrEmpty(item.CssFilePath))
  11:             ApplyThemeToControl(item, themeName);
  12:     }
  13: }

Line (10) checks if control has already set one of property, for example in design mode then theme will not be applied to such control. Last step is to modify BasePage like this …

   1: /// <summary>
   2: /// Handles the Render event of the Page control.
   3: /// </summary>
   4: /// <param name="sener">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
   6: protected virtual void Page_PreRender(object sender, EventArgs e)
   7: {
   8:     DXControlsHelper.ApplyThemeToControlsRecursively(this.Master, this.Page.StyleSheetTheme);
   9: }

.. now HTML header of rendered page looks like this.

   1: <head>
   2:   <link href="../App_Themes/WarmSky/DXControls/Editors/styles.css" type="text/css" rel="stylesheet" />
   3:   <link href="../App_Themes/WarmSky/DXControls/GridView/styles.css" type="text/css" rel="stylesheet" />
   4:   <link href="../App_Themes/WarmSky/DXControls/Web/styles.css" type="text/css" rel="stylesheet" />
   5:   <link href="../App_Themes/WarmSky/Styles/main.css" type="text/css" rel="stylesheet" />
   6:   <title>Title</title>
   7: </head>
«« Older Items • 

Get free blog up and running in minutes with Blogsome | Theme designs available here