Monday, March 1, 2010

Equal but different JavaScript style

Someone at work pointed out this surprise in JavaScript: [] == ![] evaluates to true.

Reading this I thought it was stating something is equal to the opposite of itself.  For non technical readers can things be equal without being the same?  Currencies?  People?  In English do people sometimes say same but mean equal?

In programming worlds things which are not the same might be equal, but I expect something that is the opposite of itself to definitely not be equal to itself.  For example 1 is not equal to !1  I decided to discover how can this be?

I started by firing up a debugger and looking at the types [] and ![].  ![] is false*.

Then I went to the ECMA-262 spec:

Section 11.9.1 The Equals Operator (==) points us to 11.9.3 abstract equality comparison.

11.9.3 The Abstract Equality Comparison Algorithm
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
7.If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

9.3 ToNumber
  Given Argument Type Boolean The result is 1 if the argument is true. The result is +0 if the argument is false.

Going back to 11.9.3

9. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

Section 9.1 ToPrimitive:
For input type Object

Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

Section 8.12.8 DefaultValue

When the [[DefaultValue]] internal method of O is called with hint Number, the following steps are taken:

  1. Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
  2. If IsCallable(valueOf) is true then,
    1. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list.
    2. If val is a primitive value, return val.
  3. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
  4. If IsCallable(toString) is true then,
    1. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
    2. If str is a primitive value, return str.
  5. Throw a TypeError exception.

valueOf defined in Section 15.2.4.4 does not return a primitive so toString() from step 3 is called resulting in ""

Going back to 11.9.3

5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

Section 9.3.1 ToNumber Applied to the String Type informs us that whitespace returns 0.

The leaves us with ([].toString() == "") == (![] == 0) which can be confirmed in a debugger and also results in [] == ![] resulting in true.



*To know why ![] is false
See section 11.4.9

11.4.9 Logical NOT Operator ( ! )
The production UnaryExpression : ! UnaryExpression is evaluated as follows:
1.Let expr be the result of evaluating UnaryExpression.
2.Let oldValue be ToBoolean(GetValue(expr)).
3.If oldValue is true, return false.
4.Return true.

Step 2 ToBoolean(GetValue(expr))
Takes us to Section 9.2 ToBoolean where: for Argument Type Object the result is true.

Monday, February 15, 2010

Integrating FxCop into Visual Studio

At my previous company we had Visual Studio Team System (VSTS) which has Code Analysis (FxCop) integrated into Visual Studio. To turn it on one enters project properties and clicks on the Code Analysis tab. Each rule or group of rules is turned on by checking a box and the rules execute on every build of the project. I love FxCop because it teaches me how to be a better programmer, finds issues in my code, and makes my APIs more user friendly. I was disappointed upon discovering Code Analysis is a VSTS feature.

This post shows two options for getting FxCop 1.36 running on a each Visual Studio 2008 build without maintaining an FxCop project separate from a C# project.  On the downside it will run the same set of rules for each project, which works for my scenario but may pose problems when working with legacy code and new development because the legacy code will probably violate many rules.

This instructions assume the following environment:
  • MSbuild Version 3.5.30729.4926
  • 64 bit Windows (otherwise you will need to modify the C:\Program Files (x86) paths )
  • Visual Studio 2008
  • FxCop 1.36
Option #1: Integrating FxCop at the project level.
  1. Install FxCop
  2. Create a file: C:\Program Files (x86)\MSBuild\v3.5\FxCop.targets with the following text:
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <!-- Add FxCop to the list of targets to build -->
        <BuildDependsOn>$(BuildDependsOn);FxCop</BuildDependsOn>
      </PropertyGroup>
      <!-- Define the FxCop target we added above.-->
      <Target Name="FxCop">
        <Message Text="$(MSBuildToolsPath)" />
        <!-- The Condition attribute allows others to use the same project file without breaking their build when FxCop is not installed-->
        <Exec Command="&quot;$(ProgramFiles)\Microsoft FxCop 1.36\FxCopCmd.exe&quot; /file:&quot;$(TargetPath)&quot; /console"
              Condition="Exists('$(ProgramFiles)\Microsoft FxCop 1.36\FxCopCmd.exe')" />
        <!-- When running on a 64 bit machine the $(ProgramFiles) variable will be set to c:\program files (x86) when running a 32 bit process which luckily for us Visual Studio and FxCop are.-->
      </Target>
    </Project>
  3. Open the Visual Studio
  4. File --> New Project (ctrl+shift+n)
  5. Select Other Project Types --> Visual Studio Solutions --> Blank Solution
  6. Name the solution FxCopIntegrated and press OK
  7. In Solution Explorer (ctrl +alt + L) right click the solution and select add new project.
  8. Select Visual C# --> Windows --> Class Library
  9. Name the library CodeBandit and press OK.
  10. In Solution Explorer right click the CodeBandit project and click unload project.
  11. If Visual Studio prompts to save files click "yes"
  12. In Solution Explorer right click the CodeBandit project and click "Edit CodeBandit.csproj"
  13. Navigate to the line after this (ctrl+g 52 on my machine):
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  14.  Add this line to reference the file created in step 2:
    <Import Project="$(MSBuildExtensionsPath)\v3.5\FxCop.targets"/>
  15. In Solution Explorer right click the CodeBandit project and click reload project.
  16. If Visual Studio asks to close CodeBandit.csproj click "yes" and "yes" to save changes if prompted.
  17. Build the solution.  On my system I received these warnings:
    CA2210 : Microsoft.Design : Sign 'CodeBandit.dll' with a strong name key.
    CA1014 : Microsoft.Design : Mark 'CodeBandit.dll' with CLSCompliant(true) because it exposes externally visible types.
Option #2 Integrating FxCop across all solutions.
  1. Follow the steps from Option #1 to ensure everything is setup and working.
  2. Create a file: C:\Program Files (x86)\MSBuild\v3.5\Custom.After.Microsoft.Common.targets with the following text:
    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <Import Project="FxCop.Targets"/>
    </Project>
  3. Thats it, all the work was performed in Option #1 :)
  4. To verify this add a new VB project to the FxCopIntegrated solution.
  5. Building the newly added project I get these warnings:
    CA1020 : Microsoft.Design : Consider merging the types defined in 'ClassLibrary2' with another namespace.
    CA2210 : Microsoft.Design : Sign 'ClassLibrary2.dll' with a strong name key.
    CA1014 : Microsoft.Design : Mark 'ClassLibrary2.dll' with CLSCompliant(true) because it exposes externally visible types.
    CA1824 : Microsoft.Performance : Because assembly 'ClassLibrary2.dll' contains a ResX-based resource file, mark it with the NeutralResourcesLanguage attribute, specifying the language of the resources within the assembly. This could improve lookup performance the first time a resource is retrieved.
Thanks to John Robbins for pointing me to an old post by the Code Analysis team showing how to call FxCop in a post build event and having it run over the project without maintaining a separate FxCop project file.

Monday, February 8, 2010

Redirecting Assembly Bindings in .NET 3.5

I spent some time last week digging into assembly binding redirection.  This blog post provides working examples of assembly redirection through config files and publisher policies.

This example will use the following command line utilities and versions:
  • csc - C# compiler (Version 3.5.30729.4926)
  • sn - .Strong Name Utility (Version 3.5.30729.1)
  • gacutil - Global Assembly Cache Tool (Version 3.5.30729.1)
  • al - assembly linker (Version 8.00.50727.42)
Helpful utilities not covered in this article:
To get started lets create a program calling a method in another assembly which outputs the callee's assembly version.  These steps also create assemblies for use in the later examples.
  1. Open a Visual Studio Command Prompt and navigate to a working directory where some files can be created.
  2. Create and save a file named demo.cs containing the following text:
    using System;
    using System.Reflection;

    [assembly: AssemblyVersionAttribute("2.0.0.0")]

    public static class Demo
    {
        public static void Main()
        {
            Console.WriteLine("Version " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
        }
    }
  3. from a command prompt type "sn -k key.snk"
  4. type "csc /target:library /keyfile:key.snk demo.cs"
  5. type "echo f | xcopy demo.dll .\bin\v2\demo.dll"
  6. Change the AssemblyVersionAttribute in demo.cs replacing "2.0" with "3.0"
  7. csc /target:library /keyfile:key.snk demo.cs
  8. echo f | xcopy demo.dll .\bin\v3\demo.dll
  9. Change the AssemblyVersionAttribute in demo.cs replacing "3.0" with "4.0"
  10. csc /target:library /keyfile:key.snk demo.cs
  11. echo f | xcopy demo.dll .\bin\v4\demo.dll
  12. Change the AssemblyVersionAttribute in demo.cs replacing "4.0" with "1.0"
  13. csc /target:libarary /keyfile:key.snk demo.cs
    1. echo f | xcopy demo.dll .\bin\v1\demo.dll
  14. Create and save a file named demo.cs containing the following text:
    public static class Program
    {
        public static void Main()
        {
            Demo.Main();
        }
    }
  15. csc /reference:demo.dll program.cs
  16. program.exe
  17. The output should read: Version 1.0.0.0
Redirecting 1.0 to 2.0 version in the GAC.
  1. gacutil /i .\bin\v2\demo.dll
  2. sn -T demo.dll
  3. Note the Public key token as we'll need that in the assemblyIdentity publicKeyToken attribute in the next step.
  4. Create program.exe.config with the following text:
    <?xml version="1.0"?>
    <
    configuration>
     <
    runtime>
      <
    assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <
    dependentAssembly>
        <
    assemblyIdentity name="demo" publicKeyToken="keyFromSn-T" />
        <
    bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
       </
    dependentAssembly>
      </
    assemblyBinding>
     </
    runtime>
    </
    configuration>
  5. program.exe
  6. The output should read:  Version 2.0.0.0
Redirecting 1.0 to Version 3.0 using a URL:
  1. Replace the program.exe.config text with the following:
    <?xml version="1.0"?>
    <configuration>
     <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="demo" publicKeyToken="keyFromSn-T" />
         <bindingRedirect oldVersion="1.0.0.0newVersion="3.0.0.0"/>
            <!--to use an absolute filepath use href="file://D:/Projects/...." or it can point to a web resource: href="http://www.fake.com/demo.dll"-->
         <codeBase version="3.0.0.0" href="./bin/v3/demo.dll" />
        </dependentAssembly>
      </assemblyBinding>
     </runtime>
    </configuration>
  2. program.exe
  3. The output should read: Version 3.0.0.0
Redirecting 1.0 to Version 4.0 in the GAC using a publisher policy.
  1. Create a policy.config file in the working directory with this text:
    <?xml version="1.0"?>
    <configuration>
     <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
        <assemblyIdentity name="demo" publicKeyToken="keyFromSn-T" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="4.0.0.0" />
       </dependentAssembly>
      </assemblyBinding>
     </runtime>
    </configuration>
  2. al /link:policy.config /out:policy.1.0.demo.dll /keyfile:key.snk
  3. gacutil /i policy.1.0.demo.dll
  4. gacutil /i .\bin\v4\demo.dll
  5. delete the program.exe.config in the working directory or erase the bindingredirect element.  The bindingredirects seem to be applied first and will break this example.
  6. program.exe
  7. The output should read: Version 4.0.0.0

Monday, February 1, 2010

A new life with Microsoft Dynamics CRM...

Friday January 15th was my last day at Urban Science where I learned a lot about software development and made a lot of great friends.

On Monday January 18th I started a new job at Sonoma Partners.  We specialize in customizing and implementing Microsoft Customer Relationship Management software for our customers.

If you are a technologist, programmer, personal contact, or professional contact in the Chicago area give me a call and lets get together.

If you are a potential Microsoft CRM customer, give me a call and lets make a deal ;)

Monday, January 25, 2010

NDepend

Patrick Smacchia kindly gave me the opportunity to use and evaluate his NDepend product.  NDepend is a static analysis tool meaning it can provides insight and guidance about one's work by inspecting assemblies and source code.  It identifies things like classes which may be better as structures by looking at the size of an instance of the class, the number of children, and the depth of inheritance.  It also graphically displays assembly dependencies and can do comparisons of an application between releases.  All in all a very cool tool!


First I started up NDepend to run it over a WPF desktop application I worked on in 2008.  I started by creating a new project.  It was very slick the new project open a .sln file to determine the assemblies to analyze.  NDepend understands there are application assemblies (assemblies compiled from the user's code) and tier assemblies (generally compiled references).  This picture shows what I mean.  After taking just 15 seconds to analyze 353,899 IL instructions NDepend showed an interactive view displaying many different views of the codebase at once which were all linked together, so if I drilled into something in one view or hovered over it there would be an effect in the other windows.  Being a noob this was a bit much for me and I opted to view a static HTML report.  The report didn't look so great in Chrome or FireFox but looked fine in IE8.  I read through the 50 page report awash in information.  I wish I had used the tool in 2008 to focus some of our refactoring efforts.  There are a lot of fantastic queries out of the box showing things that are blatantly wrong with the code we wrote.  Speaking of queries, NDepend has a very cool Code Query Language (CQL) one can use to write queries which throw errors or warnings during a build process.  NDepend comes with many queries out of the box which you can run or use as examples.  


Here is a query provided in the NDepend install showing types that could potentially be marked sealed:
// <Name>Class with no descendant should be sealed if possible</Name>
WARN IF Count > 0 IN SELECT TOP 10 TYPES WHERE
  
IsClass AND
  
NbChildren ==0 AND
  
!IsSealed AND
  
!IsStatic


Here is another query provided in the NDepend install showing classes that might be better as structures:

// <Name>Classes that are candidate to be turned into Structures</Name>
WARN IF Count > 0 IN SELECT TOP 10 TYPES WHERE 
  IsClass AND
  SizeOfInst <= 16 AND    // Structure instance must not be too big, else it degrades performance.
  NbChildren == 0 AND     // Must not have children
  DepthOfInheritance == 1 // Must derive directly from System.Object
  // AND IsSealed    : You might want to add this condition to restreint the set.
  // AND IsImmutable : Structures should be immutable type.
  // AND !IsPublic   : You might want to add this condition if you are developping a framework
  //                   with classes that are intended to be sub-classed by your clients.


These are two examples of things I would like to know but wouldn't like to take the effort to figure out.  NDepend makes time consuming code analysis tasks simple and shareable by providing the Code Query Language.

A couple months later I decided to use NDepend to analyze the ASP.NET solution I worked on in 2009.  I precompiled the application as recommended in the NDepend FAQ and browsed to that output instead of using the ASP.NET solution file to begin my analysis.  Unfortunately this project's code quality wasn't as high as the other project and there were 491,298 IL instructions for NDepend to analyze, although it only took 13 seconds. :)  Again I mostly skipped the UI and dove into the 492 page report.  Being a web app, some of the assemblies have funky names like App_Web_c55buezi which makes some items in the report harder to consume than the human friendly names from the desktop project.  Unfortunately I will not be working on this codebase anymore and did not have significant ownership of it so I didn't diligently read up all the goodness NDepend was giving me access to.

My lesson learned is that I need to run this fabulous tool over code I'm actively working on so I can take advantage of it and learn like I've learned from FxCop.  This tool is great because it has something for everyone.  From rules with specific recommendations on what to fix to strategic insights into your dependency structure.

Monday, December 7, 2009

Ensuring lambdas don't leak when passed to EventHandlers

I'm writing a wrapper around a class which outputs results of commands executed into a stream buffer.  I wanted to capture the command text and return that to the caller of my wrapper.  I wanted to use a lambda and clean up my delegate after the command returned.  This contrived code sample shows how to do this improperly and properly:



static void Main()
{
    ExecuteCommand();
    Debug.Assert(CommandExecuted == null);
    ExecuteCommandLeaks();
    //This assert will fail
    Debug.Assert(CommandExecuted == null);
}

static void ExecuteCommandLeaks()
{
    CommandExecuted += new EventHandler<EventArgs>((o, e) => Console.WriteLine("Event called"));

    CommandExecuted.Invoke(new object(), new EventArgs());
}

static void ExecuteCommand()
{
    var commandCapture = new EventHandler<EventArgs>((o, e) => Console.WriteLine("Event called"));
    CommandExecuted += commandCapture;

    CommandExecuted.Invoke(new object(), new EventArgs());

    CommandExecuted -= commandCapture;
}

static EventHandler<EventArgs> CommandExecuted;


Monday, November 23, 2009

SQL Server Management Studio Generating Change Scripts

For those of you who need to lookup SQL syntax for things like alter table, this will let SQL Server Management Studio (SSMS) do the work for you giving you a baseline script to modify or check right into source control.

Generating an Alter Table Statement:

  1. In SSMS use the object explorer to navigate to a table.
  2. Right click and select design.
  3. Make your changes.
  4. From the menu select Table Designer --> "Generate Change Script..."
  5. Copy and paste the script text or click the yes button to save it to a text file.

Adding a Foreign Key:

  1. In SSMS use the object explorer to navigate to a table.
  2. Expand the table node.
  3. Right click on Keys  and select "New Foreign Key..."  Notice this brings up the table designer if it isn't already open.
  4. Fill out the new FK and click Close
  5. You should now be in the table designer.  Follow the steps from above.

Monday, November 9, 2009

Delete a Blogger Comment

To delete a blogger comment, like spam, the easiest way I have found to do it is by

  1. Opening the post I want to delete in Chrome (the technique should work in any browser, but Chrome is my favorite because it is much faster than IE and because I like the Google brand better than FireFox)
  2. Right Clicking on the page and selecting "View page source"
  3. Press ctrl+f to bring up the search box and enter "delete".
  4. Look for the delete link.  It was the second search result on the page for me and looked like this: <a href='http://www.blogger.com/delete-comment.g?blogID=5094545033872573936&postID=6517665474722511356' title='Delete Comment'>
  5. Click the link.
  6. Follow the directions on the next page confirming the deletion.
There is probably a way to make the delete button show up on the page but I don't know how.

Monday, November 2, 2009

TEDxDetroit recap

My cousin, Gabriel Mott, turned me on to TED in 2005 by linking to what is still my favorite TED talk. I was excited to be accepted as an attendee of the inaugural TEDxDetroit event on 10/21/2009 at Lawrence Tech University.

The most beneficial part for me was speaking with other attendees such as Alex Fisher, Henry Balanon, Bret Kopf, Betsy Weber and meeting new people such as Lisamarie Babik, David Benjamin, Andrew Brown, Jamie Favreau, Lee Andros (bus buddy!), Janak Mehta, Rich Sheridan, and Dug Song.

Here are my take aways:

  • Ask high quality questions.  High quality questions provoke thought.  An example could be "How can we generate y revenue through x technology?",  "How can social media help solve world hunger?"
  • What can we do now given the current technology and environment?  If our plans depend on a change (new technology, etc) what if that change doesn't manifest?  If our plans don't consider the current environment (ie. culture) how will the implementation go?
  • There are two ways to make money, by nickel and diming the competition or by taking big leaps over them.  Giants take big leaps.  Who are your giants?
  • Users are not stupid. Designs are stupid.  Observer your users in their environment and reduce their pain.
  • Some people are economic hurricanes.  Everyone has great ideas.  Those who execute on those ideas are the hurricanes.
  • Research the problem before providing the solution.  When we have ideas we think of our solution and present that.  Instead of presenting that, present the problem inspiring your solution and see what others have to say.
  • At a certain level of wealth problems are problems of perception.  This was a particularly interesting talk for me because I tend to think in functional terms instead of presentation.
    • All value is relative.
    • Persuasion is better than mandates.
    • Contextual timely and immediate.
P.S. If you would like to attend a regional TED event, TEDxLansing is seeking volunteers.

Monday, October 12, 2009

Using gmail from C# and inspecting HttpRequests

This post can help you with two things

  1. Sending mail via gmail or google apps through C#.
  2. Inspecting the contents of an HttpRequest as a string similar to HttpRequest.SaveAs.


Today while working on a code for fun project at lunchtime we wanted to see the HttpContext.Request.  Initially we were calling HttpRequest.SaveAs(context.Server.MapPath("Request.txt"),true) and life was good.  When we deployed to our test server hosted by Verio, an awesome company, we got an access denied exception when trying to write.  Our corporate firewall prevented us from changing the folder permissions, and we couldn't figure out how to do it through our ftp client, FileZilla.  We decided to email the request to ourselves with the following code:

SmtpClient mailer = new SmtpClient("smtp.gmail.com", 587);
//mailer.EnableSsl = true;
mailer.Credentials = new NetworkCredential("emailAddress@yourDomain.com", "YourPassword");
mailer.Send("sender@sender.com", "recipient@recipient.com", "snazzySubject", Request.RequestAsString());

Running that code we get: System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 216.239.59.109:587.  This is our firewall blocking us again.

At home I got "The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first."

Uncommenting the mailer.EnableSsl line above and rerunning fixed the problem and my email arrived!

//End point #1 and begin point #2
Here is the code duplicating the request.saveAs functionality:  RequestAsString is an extension method.  In my code I put it in the System.Web namespace so it shows up for me when using System.Web.


/// <summary>
/// Turns an HttpRequest into a string for inspection.  Similar to request.SaveAs.
/// </summary>
/// <param name="request">The request to turn to a string.</param>
/// <returns>A string to inspect the HttpRequest.</returns>
public static string RequestAsString(this HttpRequest request)
{
    StringBuilder returnValue = new StringBuilder()
        .Append(request.HttpMethod + " " + request.RawUrl);
    if (returnValue.ToString().EndsWith("?"))
    {
        returnValue.Length = returnValue.Length - 1;
    }
    returnValue.Append(" " + request.ServerVariables["SERVER_PROTOCOL"])
        .Append(Environment.NewLine)
        .Append(TurnNamedValuesToLists(request.Headers, ": ", Environment.NewLine))
        .Append(Environment.NewLine)
        .Append(request.ContentEncoding.GetString(request.BinaryRead(request.ContentLength)));

    return returnValue.ToString();
}

/// <summary>
/// Splits out a NameValueCollection.
/// </summary>
/// <param name="target">The collection to be split.</param>
/// <param name="seperator">Seperates the key from the value in the output.</param>
/// <param name="terminator">Put at the end of the key and the value.</param>
/// <returns>A string of all the key value pairs.</returns>
private static string TurnNamedValuesToLists(NameValueCollection target, string seperator, string terminator)
{
    StringBuilder returnValue = new StringBuilder();
    string[] keys = target.AllKeys;

    foreach (var key in keys)
    {
        returnValue.Append(key + seperator + (string)target[key] + terminator);
    }
    return returnValue.ToString();
}

Monday, October 5, 2009

Useful Visual Studio 2008 Settings

Here are some Visual Studio 2008 settings I have turned on to speed up my development time.
  1. Default Browser - I use Chrome as my default browser, but our application is targeting IE.  To have Visual Studio launch IE instead of chrome I found out one can right click a .aspx page select 'Browse ' With' and then from the next dialog set Internet Explorer as default.
  2. Autorecover - Sometimes over bad VPN connections AutoRecover will freeze the VS User Interface.  I used to change the autorecover path but now I go to settings --> Environment --> Autorecover and uncheck the save checkbox.
  3. Source Control - Settings --> Source Control --> Environment  I check get everything when a solution or project is opened.  VS still prompts for get latest on open so you are in control, but it is a nice reminder to sync up.  For saving I have 'Prompt for check out' selected to avoid silent checkouts.  Some files like .vsmdi and some dependant files need to be checked out prior to editing for this to work.  For Editing I have 'Do nothing' so I can edit and continue without checking out files.
  4. Outlining - Settings -->Text Editor --> C# --> Advanced I uncheck 'Enter outlining mode when files open.'  This prevents regions from hiding code from me when I open the file.  I also uncheck 'Surround generated code with #region' because I don't like regions.  Ever.
  5. Debugging - Settings --> Debugging --> General I uncheck 'Require source files to match the original version'  This is another one for edit and continue debugging.  Sometimes I'll notice something I want to change, like changing a string literal to reference a constant from a helper class, but don't want to stop my debugging.
  6. Symbols - Settings --> Debugging --> Symbols I cache my symbols to c:\debugsymbols so they can be shared between VS and Windbg.

Monday, September 14, 2009

Catching inlining in the act from managed code.

This blog post shows ilining in action all without leaving the comfort of managed code.

When you compile C# code it is compiled to Intermediate Language (IL).  When the Common Language Runtime executes IL it uses a Just In Time (JIT) compiler to compile the IL to machine instructions.
Here is some C# sample code:


using System;
using System.Diagnostics;
static class Program
{
    static void Main() { Person me = new Person("Dave"); Console.ReadKey(); }
}
class Person
{
    public Person(string name) { Name = name; }
    private void SetName(string name)
    {
        Console.WriteLine(new StackTrace().GetFrame(1).GetMethod().Name);
    }
    public string Name
    {
        set { SetName(value); }
    }
}

Copy that code into notepad and save it as Program.cs.
From a Visual Studio command prompt type these lines.
csc /out:d.exe Program.cs /optimize- /debug+ 
csc /out:u.exe Program.cs /optimize- /debug- 
csc /out:o.exe Program.cs /optimize+ /debug- 

Then execute the programs:
d outputs set_None
u outputs .ctor
o outputs Main

Kinda crazy huh?

PS. if you run this program from Visual Studio it will output set_None because you run with a debugger attached and the JIT Compiler won't inline.  If you compile in Release mode and run without the debugger (ctrl+F5) you can see Main if you are fast enough ;)