• Kirill Osenkov

    Some resources about Visual Studio Extensibility

    • 1 Comments

    A couple of readers have posted questions about Visual Studio Extensibility, DTE, your own packages, commands, experimental hive etc. To be frank, I’m not an expert in this field, so instead of trying to answer these questions, I will point to some better resources for VSX (VS Extensibility):

  • Kirill Osenkov

    Should Call Hierarchy display compiler-generated member calls?

    • 3 Comments

    [A quick reminder, Call Hierarchy is a new IDE feature in VS 2010]

    In the comments to the previous post, a reader is asking:

    But why are the query operator method calls ignored by the Call Hierarchy?

    var r = from i in new[] { 1, 2, 3 }

           where i > 1

           select i;

    The code snippet above calls Enumerable.Where and Enumerable.Select, and I reacon they should go into Call Hierarchy, which is not the case of the current beta. Any hint on this?

    This is actually a good question. We thought about this issue in the feature design meetings and the reasoning behind the decision not to show the LINQ methods was as follows. The foreach statement also calls GetEnumerator and MoveNext, lock calls Monitor.TryEnter (or something similar??), not to mention other places where compiler-generated code calls members (e.g. the yield return state machine, lambdas, etc). The question is simple: where do we stop? In other words, how deep do we go down the abstraction ladder?

    This also applies to things like calling += on events, which actually calls Delegate.Combine, calling a delegate calls the Invoke method, etc. etc. We decided that we will only show a member call in Call Hierarchy if the compiler actually sees the member’s symbol in the source code. Find All References also follows this pattern, e.g. if you look for Point, you will have two references in Point p = new Point(); and only one reference in var p = new Point(); – since the symbol doesn’t show up in your source code, we don’t mention it. This might be misleading actually, also when you’re looking for calls to a method, we won’t show you places where you create a delegate that points to this method (or method group).

    Do you think this reasoning is OK or would you like us to change the feature’s behavior? If yes, how exactly should it behave? Also keep in mind that changing this behavior at this point will be pretty costly (i.e. I will have to retest everything!). Not even to mention that our dev will have to change the implementation :)

    Thanks!

  • Kirill Osenkov

    Visual Studio 2010 Beta 1 is out!

    • 2 Comments

    In case you missed it (which I don’t believe), today we released Visual Studio 2010 Beta 1 to MSDN subscribers. On Wednesday, it will become available for everyone else to download.

    The build is much more stable and fleshed out then the early CTP preview – I’d say, the functionality of Visual Studio 2010 is at least 95% there already. Our next top priority is fixing performance and making VS fast, sleek and snappy. But it already got its new WPF “skin”, the brand-new WPF editor, historical debugger, architecture explorer, and of course, C# 4.0 and VB 10 new language and IDE features. Also, for the first time ever, F# is in the box just like C# and VB.

    In any case – go try it out and tell us what you think. If you have anything to say about the new C# Call Hierarchy toolwindow – let me know.

  • Kirill Osenkov

    A simple sample for C# 4.0 ‘dynamic’ feature

    • 11 Comments

    Earlier I posted some code to start Visual Studio using C# 3.0:

    using System;
    using EnvDTE;
    
    class Program
    {
        static void Main(string[] args)
        {
            Type visualStudioType = Type.GetTypeFromProgID("VisualStudio.DTE.9.0");
            DTE dte = Activator.CreateInstance(visualStudioType) as DTE;
            dte.MainWindow.Visible = true;
        }
    }

    Now here’s the code that does the same in C# 4.0:

    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            Type visualStudioType = Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
            dynamic dte = Activator.CreateInstance(visualStudioType);
            dte.MainWindow.Visible = true;
        }
    }

    At first, it looks the same, but:

    1. Referencing EnvDTE.dll is not required anymore – you also don’t need using EnvDTE – don’t need to reference anything!
    2. You declare the ‘dte’ variable to be weakly typed with the new dynamic contextual keyword
    3. You don’t have to cast the instance returned by Activator.CreateInstance
    4. You don’t get IntelliSense as you type in the last line
    5. The calls to dte are resolved and dispatched at runtime

    It’s a trade-off, but I still view dynamic as yet another useful tool in the rich C# programmer’s toolbox to choose from.

  • Kirill Osenkov

    Jon Skeet: Planning C# In Depth 2

    • 8 Comments

    Jon is asking advice about how to shape the second edition of his book “C# In Depth”. Jon, I like your current suggestions (in blue) about making tweaks to existing content and adding a new section on C# 4.0.

    One thing I’d also love to see is a summary of the hypothetical C# vNext features that the community has been discussing in the blogosphere and on the forums. I think Jon is the right person to come up with a great summary of those features, the rationale behind them, and possible implementation (syntax).

    Specifically, I’m talking about:

    1. Immutability (e.g. public readonly class) and related matters (initializing auto-props, using tuples as an implementation for anonymous types, making object initializers immutable, tuples in the language etc.). Also statically verifying immutability etc.
    2. yield foreach and allowing anonymous methods to be iterators (like a VB prototype that Paul Vick blogged about)
    3. return type covariance
    4. duck typing, making a type implement an interface without touching it’s source, techniques (TransparentProxy, Reflection.Emit etc)
    5. member-level var (hopefully we won’t have this)
    6. notnull, code contracts in the language
    7. traits/mixins (e.g. redirecting an interface’s implementation to a field/property that implements that interface)
    8. metaprogramming (syntactic/semantic macros, DSLs in the language, infoof, compile-time reflection, IL rewriting (PostSharp, CCI, Mono.Cecil), AOP, transformations, code generation)
    9. parallel programming, concurrency, etc.
    10. Am I missing something?
  • Kirill Osenkov

    Common Compiler Infrastructure released on CodePlex

    • 2 Comments

    Great news – Herman Venter from Microsoft Research has released CCI (Common Compiler Infrastructure) on CodePlex: http://ccimetadata.codeplex.com. See Herman’s blog post here.

    The Microsoft Research Common Compiler Infrastructure (CCI) is a set of components (libraries) that provide some of the functionality that compilers and related programming tools tend to have in common.

    The metadata components provide functionality for reading, writing and manipulating Microsoft Common Language Runtime (CLR) assemblies and debug files. The functionality provided by these components subsumes the functionality provided by System.Reflection and System.Reflection.Emit.

    It’s interesting to know that FxCop is actually powered by CCI, so if you wondered how FxCop analyzes your assemblies, you can now peek into the source code and even build your own tools that leverage the CCI framework.

    Update:

    Beside the metadata rewriting engine and IL/PDB/PE framework, CCI also provides the AST and syntax trees to model source code, IL <-> CodeModel roundtripping, C# pretty-printer, as well as SmallBasic compiler as a sample.

    See here:

  • Kirill Osenkov

    Remote Desktop: /span across multiple monitors

    • 23 Comments

    I spent some time searching the web about Remote Desktop, fullscreen and multiple monitors, so I decided to write down my findings to avoid having to search for them again.

    /span for multiple monitors

    If you pass /span to mstsc.exe, the target session’s desktop will become a huge rectangle that equals to the summary area of your physical monitors. This way the remote desktop window will fill all of your screens. The downside of this approach is that both screens are part of one desktop on the remote machine, so if you maximize a window there, it will span all of your monitors. Also, a dialog that is centered, will show up right on the border between your monitors. There is software on the web to workaround that but I’m fine with keeping my windows restored and sizing them myself. Also Tile Vertically works just fine in this case.

    Saving the /span option in the .rdp file

    There is a hidden option that isn’t mentioned in the description of the .rdp format:

    span monitors:i:1

    Just add it at the bottom of the file.

    Saving the /f (fullscreen) option in the .rdp file

    screen mode id:i:2

    (By default it’s screen mode id:i:1, which is windowed).

    Sources

  • Kirill Osenkov

    DLR Hosting in Silverlight

    • 9 Comments

    As you probably know, DLR is the dynamic language runtime that provides a common platform for dynamic languages and scripting in .NET. Their two main languages, IronPython and IronRuby, are available to develop your programs and also to be hosted in your programs. DLR hosting means that the users of your program can use scripting in any DLR language, for example to automate your program or to programmatically access the domain model of your application.

    I was thinking about adding a capability to plot function graphs like y = cos(x) to my Live Geometry app, so I thought of hosting the DLR in Silverlight to compile and evaluate mathematical expressions.

    Fortunately, DLR readily supports this scenario. And fortunately, Tomáš Matoušek, a developer on our IronRuby Team (part of Visual Studio Managed Languages), sits right around the corner from my office and was kind enough to provide great help when I had questions. Big thanks and kudos to Tomáš!

    So, to host the DLR in Silverlight, here's the file that I added to my project (you can view my full source code here: http://dynamicgeometry.codeplex.com/SourceControl/ListDownloadableCommits.aspx).

    All you need to do is to set up a script runtime, get your language's engine (here we use Python), create a scope for your variables and you're ready to evaluate, execute and compile!

    using System;
    using DynamicGeometry;
    using IronPython.Hosting;
    using Microsoft.Scripting.Hosting;
    using Microsoft.Scripting.Silverlight;
    
    namespace SilverlightDG
    {
        public class DLR : ExpressionCompiler
        {
            ScriptRuntime runtime;
            ScriptEngine engine;
            ScriptScope scope;
    
            public DLR()
            {
                var setup = new ScriptRuntimeSetup();
                setup.HostType = typeof(BrowserScriptHost);
                setup.LanguageSetups.Add(Python.CreateLanguageSetup(null));
    
                runtime = new ScriptRuntime(setup);
                engine = runtime.GetEngine("Python");
                scope = engine.CreateScope();
    
                engine.ImportModule("math");
            }
    
            public override Func<double, double> Compile(string expression)
            {
                var source = engine.CreateScriptSourceFromString(
                    string.Format(@"
    from math import *
    
    def y(x):
        return {0}
    
    func = y
    ", expression),
                    Microsoft.Scripting.SourceCodeKind.File);
    
                CompiledCode code = source.Compile();
                code.Execute(scope);
                var func = scope.GetVariable<Func<double, double>>("func");
                return func;
            }
        }
    }

    ExpressionCompiler is my own abstract class that I defined in the DynamicGeometry assembly:

    using System;
    
    namespace DynamicGeometry
    {
        public abstract class ExpressionCompiler
        {
            public abstract Func<double, double> Compile(string expression);
            public static ExpressionCompiler Singleton { get; set; }
        }
    }

    As you see, the service that I need from the DLR is to implement the Compile method, that compiles an expression down to a callable function delegate, which I can then use to evaluate a function at a point.

    Finally, just register the DLR as an implementation for my ExpressionCompiler:

    ExpressionCompiler.Singleton = new DLR();

    And we're ready to go.

    Let's go back to the DLR.cs and I'll comment a little more on what's going on. Essentially, to host the DLR you'd need 3 things:

    ScriptRuntime runtime;
    ScriptEngine engine;
    ScriptScope scope;

    Runtime is your "world". You load a language-specific engine (like PythonEngine) into the runtime. To create a runtime with a language, one way is to use:

    var setup = new ScriptRuntimeSetup();
    setup.HostType = typeof(BrowserScriptHost);
    setup.LanguageSetups.Add(Python.CreateLanguageSetup(null));
    runtime = new ScriptRuntime(setup);

    This will work fine in Silverlight, because we use a browser-specific BrowserScriptHost, which does not use the file system. One problem that I had is that I was trying to directly call:

    runtime = Python.CreateRuntime();

    Which didn't work because it used the default script host (which tried to access the file system) and not the BrowserScriptHost. After you have the runtime, you can get the engine and create a scope in that engine:

    engine = runtime.GetEngine("Python");
    scope = engine.CreateScope();

    Now you're ready to do things like:

    var five = engine.Execute("2 + 3", scope);
    You can go up to the first code example to see how I declared a function in Python, and converted it to a C# callable Func<double, double> delegate.

    Finally, here's the working application (which you can also find at http://geometry.osenkov.com). Press the y = f(x) toolbar button, enter sin(x) and press the Plot button:

  • Kirill Osenkov

    Visual Studio 2010 Screencast: C# 4.0 Language + IDE + WPF Shell + Editor

    • 13 Comments

    It so happened that I recorded a quick 30-minutes video (screencast) showing the new features in the language and the IDE – and I did all this on a recent internal build of Visual Studio 2010, which has the WPF UI enabled. The video is very basic, I don’t go into any details, it’s mainly a quick overview and how features look like:

    Get Microsoft Silverlight

    You can also download or view the .wmv file here: http://guilabs.de/video/CSharp4.wmv

    Features covered:

    1. Language (0:00)
      1. Dynamic (0:30)
      2. Named and optional (3:20)
      3. Co/Contravariance (11:10)
      4. NoPIA, omit ref etc. (16:35)
    2. IDE (18:45)
      1. Call Hierarchy (18:50)
      2. Quick Symbol Search (23:00)
      3. Highlight References (25:30)
      4. Crash!! (26:15)
      5. Generate From Usage (26:50)
      6. fix aggressive IntelliSense (consume first, list filtering) (29:50)
  • Kirill Osenkov

    Kirill’s Whitespace Guidelines for C#

    • 16 Comments

    I don’t remember seeing any explicit guidelines on whitespace formatting for C# programs, however it seems that experienced C# developers all format their C# code files in a very similar fashion, as if there are some implicit but widely-accepted rules. In this post, I’ll try to formalize my own rules that I use intuitively when I format C# code. I’ll add more to it as I discover new stuff and correct things based on your feedback.

    No two consecutive empty lines

    Bad:

       1:  static void Main(string[] args)
       2:  {
       3:      Main(null);
       4:  }
       5:   
       6:   
       7:  static void Foo()
       8:  {
       9:      Foo();
      10:  }

    No empty line before a closing curly

    Bad:

       1:          Main(null);
       2:   
       3:      }

    No empty line after an opening curly

    Bad:

       1:  class Program
       2:  {
       3:      
       4:      static void Main(string[] args)

    One empty line between same level type declarations

       1:  namespace Animals
       2:  {
       3:      class Animal
       4:      {
       5:      }
       6:   
       7:      class Giraffe : Animal
       8:      {
       9:      }
      10:  }

    One empty line between members of a type

       1:  class Animal
       2:  {
       3:      public Animal()
       4:      {
       5:      }
       6:   
       7:      public void Eat(object food)
       8:      {
       9:      }
      10:   
      11:      public string Name { get; set; }
      12:  }

    Whereas it’s OK to group single-line members:

       1:  class Customer
       2:  {
       3:      public string Name { get; set; }
       4:      public int Age { get; set; }
       5:      public string EMail { get; set; }
       6:   
       7:      public void Notify(string message)
       8:      {
       9:      }
      10:  }

    However every multi-line member must be surrounded by an empty line unless it’s the first or the last member, in which case there shouldn’t be a line between the member and the curly brace.

    One empty line after #region and before #endregion

    Usually #region should be treated as if it were the first construct from it’s content (in this example, a type member):

       1:  class Customer
       2:  {
       3:      #region Public properties
       4:   
       5:      public string Name { get; set; }
       6:      public int Age { get; set; }
       7:      public string EMail { get; set; }
       8:   
       9:      #endregion
      10:   
      11:      public void Notify(string message)
      12:      {
      13:      }
      14:  }

    Within a #region, it’s contents should be separated from the #region/#endregion by a single empty line. Usually #regions contain type members or whole types, less often parts of a method body.

    I think these are the major rules that come into mind for now. If I remember more, I’ll update this post. Also, definitely feel free to contribute any corrections/additions and I’ll update the post too. Thanks!

  • Kirill Osenkov

    A common globalization bug

    • 1 Comments

    I’ve just found and fixed a globalization bug in our test infrastructure where a feature of our testcase management system (resetting a testcase to re-run on a lab machine) just wouldn’t work on a Russian OS. Fortunately, the call stack was easy to investigate: (sorry it’s in Russian - globalization, what can you do…)

    System.InvalidCastException: Приведение строки "2.0" к типу "Double" является недопустимым. ---> System.FormatException: Входная строка имела неверный формат.
       в Microsoft.VisualBasic.CompilerServices.Conversions.ParseDouble(String Value, NumberFormatInfo NumberFormat)
       в Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
       --- Конец трассировки внутреннего стека исключений ---
       в Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
       в Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value)
       в XXXXXXXX.Utilities.DotNetFramework.IsDotNetFramework35HigherInstalled()
       в XXXXXXXX.Result.BulkResetResultsHelper(...

    This essentially says: cannot convert a string “2.0” to double. Here’s the problem line of code (VB):

    version = CDbl(numbers(0) & "." & numbers(1))

    and here’s a fix:

    version = System.Double.Parse(numbers(0) & "." & numbers(1), System.Globalization.CultureInfo.InvariantCulture)

    The original code made an incorrect assumption that the decimal separator in the current culture is the ‘.’ character. However on German, Russian, Italian and some other OSs the default decimal separator is a ‘,’, not a ‘.’. By default, string operations use the current locale (and hence expect a comma as a decimal separator), so if you want to compose a string using a dot and convert it to a double, you have to use InvariantCulture, which uses a dot.

    I’ve seen this error quite a lot of times – this is probably the most common globalization bug out there. Keep in mind, it’s 21st century out there, it’s likely that your software will be used all over the world on all possible combinations of operating systems, languages, locales, encodings, RTL etc.

    A good read on this topic would be Jeffrey Richter’s CLR via C#, chapter 11 (Chars, Strings, and Working with Text), pages 264-268).

  • Kirill Osenkov

    How to start Visual Studio programmatically

    • 6 Comments

    One of the ways we test Visual Studio is by automating the devenv.exe process using a library called DTE (Design Time Extensibility). To use this library from your .NET application, you’ll need to add a reference to the EnvDTE assembly (which is usually available on the .NET tab of the Add Reference dialog).

    Starting Visual Studio using DTE

    Here's a simple code snippet that starts Visual Studio and displays its main window:

    using System;
    using EnvDTE;
    
    class Program
    {
        static void Main(string[] args)
        {
            Type visualStudioType = Type.GetTypeFromProgID("VisualStudio.DTE.9.0");
            DTE dte = Activator.CreateInstance(visualStudioType) as DTE;
            dte.MainWindow.Visible = true;
        }
    }

    When the VS object is being created, a VS process (devenv.exe) starts in the background. You can make its main window visible using dte.MainWindow.Visible = true;

    Note that when the parent process (your program) ends, VS will close with it as well.

    To get an instance of an already running VS process, you can use the following snippet:

    EnvDTE80.DTE2 dte2 = (EnvDTE80.DTE2)
        System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.9.0");

    This snippet also demonstrates using DTE2, a newer version of the DTE interface that provides additional functionality.

    DTE interface

    Since DTE is COM based, we need to get the type that represents DTE from a well-known ProgID (“VisualStudio.DTE.9.0” that can be found in the registry). Once we have that type, we create an instance of it using Activator and cast it to the DTE interface. Contrary to what the name suggests, DTE is actually an interface and not a class:

    namespace EnvDTE
    {
        [CoClass(typeof(DTEClass))]
        [Guid("04A72314-32E9-48E2-9B87-A63603454F3E")]
        public interface DTE : _DTE
        {
        }
    } 

    DTE commands

    Now that you have DTE in your hands, you can do a whole lot of stuff, for example, execute a command:

    dte.ExecuteCommand("File.OpenFile", "");

    This one will execute the File.OpenFile command to display the open file dialog. There are plenty more Visual Studio commands that are really useful if you want to automate Visual Studio. You can look up a VS command from the Command Window: View –> Other Windows –> Command Window. Just start typing there and it will offer a completion list:

    image

    Also, you can use the Customize dialog (right-click on any VS menu) to get an idea of what commands are available:

    image

    Finally, you can see what command corresponds to an action if you start recording a macro, then just do an action manually, and then view the source code for that macro. As the macro is being recorded, VS registers all DTE command calls and writes them down in VBA source code. For example, ever wondered what command corresponds to the Rename refactoring? Record it and view the macro source, you’ll find out that there is a Refactor.Rename command.

    Other DTE API

    Apart from DTE.ExecuteCommand, there are a lot of other APIs to control the editor, ActiveDocument, ActiveWindow, Application, Debugger, Documents, ItemOperations, Solution, SourceControl, etc.

    However this deserves a separate post by itself. Who knows, if there is popular demand on how to automate Visual Studio, I might start a series of blog posts about that. However, for now, I’ll just link to MSDN articles on DTE:

  • Kirill Osenkov

    Making the XAML editor fast

    • 0 Comments

    If you use WPF/Silverlight and prefer working with XAML only (i.e. no visual designer), you can significantly, I repeat, significantly speed-up the XAML editor. Check out this tip from Fabrice Marguerie: Life changer XAML tip for Visual Studio

  • Kirill Osenkov

    What's common between C# 4.0 optional parameters, object initializers, the new WPF code editor and the navigation bar comboboxes?

    • 1 Comments

    I found an interesting bug recently which resulted from a pretty weird constellation of the following Visual Studio features:

    1. C# 4.0 optional parameters
    2. object initializer syntax
    3. the VS code editor rewritten from scratch in managed code and WPF
    4. the navigation bar combobox updated to show default values for optional parameters

    Here's the screenshot of the bug:

    image

    If you pasted this code in a recent VS 2010 build, the navigation bar (two comboboxes above) would grow to accomodate the full text of the Main method. Why?

    Here's what happens:

    1. The code contains a parse error (missing closing parenthesis after new Program())
    2. The IDE parser (which is very resilient) parses the entire Main method body as the object initializer on the default value of Program
    3. Since during the parsing stage we don't apply certain compiler checks yet, the parser assumes that an object creation expression with an object initializer is a valid default value for the optional parameter
    4. it takes the entire text of the parameter (including the default value and the initializer) and passes it to the New Editor for displaying in the navigation bar as part of Main's signature
    5. the New Editor's navbar comboboxes aren't simply textboxes - they are instances of the full-blown WPF New Editor control themselves
    6. since they're so powerful, they have absolutely no problem displaying multiline content
    7. the rest of the WPF layout shifts accordingly to accomodate the growing content

    We hope to fix the bug before VS 2010 Beta 2 (probably not Beta1 because it's a low impact low priority).

  • Kirill Osenkov

    How to Debug Crashes and Hangs translated into Chinese

    • 0 Comments

    Big thanks to He,YuanHui who has translated my debugging tutorial into Chinese:

    http://www.cnblogs.com/khler/archive/2009/02/08/1386462.html

    Enjoy!

  • Kirill Osenkov

    New Years resolutions v2.0.0.9

    • 3 Comments

    Well, I've been tagged in a chain-letter-blogging game again. This time, Chris "I-like-to-put-ugly-monsters-on-the-frontcovers-of-my-books-to-at-least-partially-distract-readers-from-great-content" Smith tagged me in his New Years resolutions post. It's February, but I think it's better late than never. So here it goes:

    Make sure VS 2010 rocks!

    I'll try to do my part and make sure that our language service works as expected and the features are pleasant to work with. I'll also try to make sure other teams don't miss obvious bugs (yes, Editor, Shell and Project System, I'm looking at you!) Given the fact that I keep finding crashes in the XAML designer, I'll keep an eye on them as well. Oh and the debugger, of course.

    Learn MEF

    I plan to read MEF sources and actually play with it. It's 21 century out there, nowadays you *need* a dependency injection/component framework.

    Learn DLR

    Especially DLR hosting. Would be fun to build an expression evaluator/function graph plotter into my Live Geometry Silverlight app.

    Read more of the product code

    I definitely should read more of the VS source, especially since more and more of it gets rewritten in managed code. We're building a managed compiler and rewriting the language service in managed code, it would be great to follow the API design there. It's super important to get the API surface right. I'll maybe start playing with it early on and build some sample apps/add-ins to see how the API feels.

    Read more blogs

    and catch up on all those starred and flagged items. I plan to read all of Cyrus, all of Wes and all of Eric, for a start. I need to catch up on Jon's early posts as well. Also, I still hope Wes starts blogging again. Same for Dustin (although I do understand how busy Dustin is in his new role...)

    Gym

    Continue ignoring it. I'll at least be honest to myself. I will still exercise regularly. Once in three months is regular, isn't it?

     

    Is there anything else that I've missed? :-P

  • Kirill Osenkov

    ForEach

    • 13 Comments

    In my recent post about coding styles one particular thing provoked the majority of feedback and discussions: the ForEach extension method on IEnumerable<T>. Justin Etheredge has a good post about this method here. StackOverflow.com also has a good question: Why is there not a ForEach extension method on the IEnumerable interface?

    Note: If you’d like this method to be added to .NET 4.0, go vote here: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093

    Recently I also went ahead and logged a suggestion against the BCL team to add this method in .NET 4.0, and got some feedback from Melitta Andersen and Justin van Patten. Essentially, the BCL team’s considerations boil down to what we’ve discussed in my recent post:

    • it encourages state mutation
    • it’s hard to set a breakpoint inside the lambda/delegate body (and other debugging issues)
    • it’s not clear where to place this method (it’s not exactly part of LINQ, it’s just a helper on IEnumerable<T>), also it doesn’t allow to chain calls

    Mads Torgersen (representing the language design team) was also reluctant about adding this method because of similar concerns (functional impurity etc). I myself in my previous post was enumerating various downsides of using this method.

    And still I think we should add it.

    My thinking is the following. The ultimate purpose of the BCL is to help avoid code duplication by introducing a common reusable set of functionality so that people don’t have to reinvent the wheel by writing their own collections, sorters, etc. A lot of people will use ForEach anyway, and if we don’t provide it in the framework, they will have to re-implement it in every new project. Also, by providing the ForEach method out of the box, we’re not forcing anyone to actually go ahead and use it – people will still have the choice and be warned about the downsides of ForEach. It’s just when they will use it anyway (and this happens a lot), they will be able to consume a ready-made one. The use of having it (in my opinion) by far overweights the downsides of using it inappropriately.

    ForEach looks really good with very simple snippets, such as:

    myStrings.ForEach(Console.WriteLine);

    Some developers forget that you can use this shorter syntax instead of:

    myStrings.ForEach(s => Console.WriteLine(s));

    Another ForEach advantage is that it allows you to extract the body of the loop into a separate place and reuse it by just calling into it.

    Also, given the fact that List<T> already has it, it seems unfair that IEnumerable<T> doesn’t. This is an unnecessary limitation (that’s what I think).

    Chris Tavares says:

    I suspect the reason that this didn't exist before is that you can't use it from VB. VB only support lambda expressions, while the foreach method requires a lambda *statement*.

    Well the good news is that we are introducing statement lamdbas in VB 10.0 so this shouldn’t be an issue at all.

    I’m also pretty sure that one can also overcome the debugging difficulties of ForEach with tooling support, such as [DebuggerStepThrough] and “Step Into Specific”. Debugging problems are not language/libraries problem per se, it’s a tooling problem, and tooling should always be fixed/improved to satisfy languages and libraries.

    A lot of people are asking for the ForEach extension method – this is probably one most wanted piece of API:

    My questions for you folks are:

    1. What do you think? Should this method be added to BCL?
    2. If yes, where? System.Linq.Enumerable? System.Collections.Generic.Extensions? Anywhere else?

    There are also variations on this extension method:

    • returning IEnumerable<T> to allow the ForEach calls to chain
    • accepting an Action<T, int> where the second parameter is the index of an item
    • Kevin’s Apply method

    If you ask me, only the simplest overload should be added, because Select is a better choice for chaining calls. Also this would encourage people to use the method in the simplest scenarios, where the downsides of doing so are negligible.

    Finally, one argument I have is that googling “foreach extension method” yields 1 590 000 results, which I think is a pretty good indication that the feature has high demand.

  • Kirill Osenkov

    How to disable optimizations during debugging

    • 3 Comments

    Sooner or later you may run into a situation where you need to evaluate a local variable under debugger and all you get is this:

    "Cannot obtain value of local or argument 'whatever' as it is not available at this instruction pointer, possibly because it has been optimized away'.

    Well, it turns out there are two different tricks to solve such problems:

    1.

    Shawn Burke blogs about How to disable optimizations when debugging Reference Source. In a nutshell, you need to:

    1. Start VS with the Environment Variable COMPLUS_ZapDisable=1
    2. Disable the VS Hosting Process (.vshost.exe) before you start debugging

    2.

    Another tip is from our VB IDE Dev Jared Parsons: Disabling JIT optimizations while debugging. Essentially, Jared points to create an .ini file with the same name as the application's .exe:

    [.NET Framework Debugging Control]
    GenerateTrackingInfo=1
    AllowOptimize=0

    He also points to the MSDN article http://msdn.microsoft.com/en-us/library/9dd8z24x.aspx (Making an Image Easier to Debug).

    To be frank, this tip didn't work for me for some reason, but I guess it's still worth mentioning.

    Hope this helps!

  • Kirill Osenkov

    Call Hierarchy Navigation in Visual Studio 2010

    • 31 Comments

    We're currently designing a new IDE feature named Call Hierarchy. Essentially, it allows you to find places where a given method is called, which is similar to how Find All References currently works. However, unlike Find All References, the Call Hierarchy feature provides more deep understanding and more detailed information about calls.

    Invocation

    You can invoke the Call Hierarchy toolwindow by right-clicking on a method, property or constructor name in the code editor and choosing View Call Hierarchy from the context menu:

    image

    Tool window

    A toolwindow will appear docked on the bottom of the Visual Studio window:

    image

    You can expand the node for the method to see information about it: incoming calls to the method ("Calls To") and outgoing calls ("Calls From"):

    image

    Here's how it works. A method (or a property, or a constructor) is displayed as a root in the treeview. You can expand the node to get a list of "search categories" - things you want to find. Four search categories are currently supported:

    1. Calls To - "incoming" calls to this member
    2. Calls From - "outgoing" calls mentioned in this member's body
    3. Overrides - available only for abstract or virtual members
    4. Implements - finds places where an interface member is implemented

    When you expand a search node (such as Calls To 'GetCallableMethods'), a solution-wide search is started in the background and the results appear under the Calls To folder. You can click on a result, and the details will appear in the Details list view on the right hand side.

    The Details list view shows all the exact call sites and locations in code where GetCallableMethods is called from GenerateXsdForComplexTypes. We see that the method is being called only once, the line of code is shown, as well as file name and position in the file. Double-clicking on that call site will navigate to it in the code editor.

    The advantages of Call Hierarchy compared to Find All References is that it allows you to explore and drill deep multiple levels into the call graph (find caller's caller etc.) Also, Call Hierarchy has deeper and more fine-granular understanding of the source code - while Find All References just finds the symbols, Call Hierarchy differentiates abstract and virtual methods, interface implementations, actual calls from delegate creation expressions, etc. Also it works like a scratch-pad: you can add any member as another root-level item in the call hierarchy tool window and have several members displayed there at once. Finally, the Details Pane given information about the concrete call sites, if a method is being called several times in the body of the calling method.

    Toolbar

    In the toolbar you can select the scope of the search: search in currently opened file only, current project or the entire solution.

    Refresh button re-fills the treeview in case the original source code was modified.

    If a root node of the treeview is selected, the "Delete Root" button will remove it from the treeview. You can add any member as a new root in the treeview by right-clicking on it in the context menu:

    image

    or adding it from the source code as described in the beginning.

    Finally, the Toggle Details Pane button shows or hides the details pane.

    Some design issues and implementation details

    Although the feature is already implemented and if you have the Visual Studio 2010 CTP, you can already play with Call Hierarchy, we're still not quite happy with the current UI design, usability and the user experience.

    For example, one issue that we're seeing is that it takes 2 mouseclicks and 2 mousemoves to invoke the Find All References search, but it takes 4 mouseclicks and 4 mousemoves to get the callers list for a given method (1 click - menu invocation, 1 click - menu item selection, 1 click - expand the treeview node for the method, 1 click - expand the "Calls To" folder). Although the search itself will be slightly faster than Find All References, the perceived complexity of invoking the feature is something we definitely want to improve. We want this feature to be at least as good and usable as Find All References, but also provide additional benefits, otherwise people will just not use the feature and continue using Find All References.

    I think I'll stop for now and see what kind of feedback you guys might have about this. In the next blog post I plan to share more of our current thinking and what we'd like to change. For now, I'd be really interested to know what you think and if you have any suggestions or ideas. Now it's not too late, and we can change the feature based on your feedback.

  • Kirill Osenkov

    Reflections on coding style

    • 15 Comments

    I've been monitoring my coding style for quite a while and I noticed that I often prefer chaining method calls to normal control flow. Now I think it might not always be such a good idea.

    To give you an example, today I had a task of reflecting over constants in a class and stuffing them into a dictionary. Here's a sample to demonstrate my original approach. In this sample I replaced the actual domain model with a fake colors domain and the task is to implement two methods: FillColors and OutputColors.

    using System;
    using System.Collections.Generic;
    
    static class Program
    {
        public const string Red = "#FF0000";
        public const string Green = "#00FF00";
        public const string Blue = "#0000FF";
    
        static void Main(string[] args)
        {
            var dictionary = new Dictionary<string, string>();
            FillColors(dictionary.Add);
            OutputColors(dictionary);
        }
    
        static void FillColors(Action<string, string> add)
        {
            var fields = typeof(Program).GetFields();
            fields.ForEach(f => add(f.Name, f.GetRawConstantValue().ToString()));
        }
    
        static void OutputColors(Dictionary<string, string> dictionary)
        {
            dictionary.ForEach(p => Console.WriteLine(p.Key + " = " + p.Value));
        }
    
        static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
        {
            foreach (var item in list)
            {
                action(item);
            }
        }
    }

    First, several interesting comments about the code.

    • constants are public because otherwise Type.GetFields won't find them. And for the life of me I couldn't figure out how the overload of GetFields works that accepts BindingFlags. I didn't want to spend more than 2 minutes on that so I just made the constants public.
    • there are no more access modifiers, because members are private by default and top-level types are internal by default if the access modifier is missing. Jon Skeet wrote in his C# in Depth book that he prefers omitting the modifier if it corresponds with the default visibility and I really like this style. Makes the programs shorter. Short programs are especially useful for us testers, where we need to find a minimal repro for bugs that we report.
    • FillColors accepts a delegate "add" which I like calling "the collector". It could have accepted the entire dictionary, but I only use the add functionality so to minimize coupling I only require what I actually consume. An alternative here would be to implement an iterator using yield return, but this would require returning a list of pairs of values, and Tuples were not in our TFS branch yet at the moment of writing :) Another reason for "the collector" pattern is that yield return doesn't compose well - flattening lists like Comega does is still not in C# as of 4.0. Contrary to that, passing a delegate (Continuation-Passing Style) composes nicely and is fully supported starting from C# 1.0.
    • OutputColors doesn't accept IEnumerable<KeyValuePair<string, string>> because I was to lazy to spell that out and it is not relevant to the current discussion :)
    • Also OutputColors doesn't accept Action<string> and hardcodes Console.WriteLine because of the KISS/YAGNI principle.
    • I don't know why KISS/YAGNI didn't apply to the FillColors method. It just didn't.

    But I digress. Let's go back to the actual topic of me writing one long line:

    fields.ForEach(f => add(f.Name, f.GetRawConstantValue().ToString()));

    instead of:

    foreach (var f in fields)
    {
        add(f.Name, f.GetRawConstantValue().ToString());
    }

    Here are several observations that favor foreach against ForEach:

    ForEach is not in the library

    As of .NET 3.5 SP1, ForEach is not in the library so I had to implement it myself. For .NET 4.0 I've logged a suggestion with Mads to add it to the BCL, but I'm not sure if we're adding it for 4.0. A lot of people seem to add it to their libraries so I think it'll be useful to have regardless of the coding style it suggests. I'm sure it is useful at least sometimes.

    ForEach hides state mutation

    Eric Lippert told me that he's not a great fan of ForEach because it conceals state mutation - it takes an eager (non-lazy) control flow statement that mutates state and hides it behind a functionally-looking call.

    You can't put a breakpoint inside ForEach "body"

    If you use foreach, you can put a breakpoint on the add call, whereas you can't put a breakpoint on the add call in the first case. This is not a language problem, but rather a tooling issue, but still I don't see tools (yes, debugger, I'm looking at you!) becoming comfortable enough in this scenario anytime soon.

    Stack is polluted

    In the first case (ForEach), two additional frames are on the stack which looks kinda ugly during debugging:

    image

    vs. the original:

    image

    This may not have a good impact on the debugging story.

    Performance is worse

    Although I know that micro-managing performance is a bad thing to do, we still create an anonymous method (metadata bloat) and have two additional calls on the stack (I know that JIT will probably optimize them, but who knows). So the danger is that in critical codepaths (bottlenecks) the performance will degrade compared to using control flow (which the JIT will compile into a couple of nice fast JMP instructions).

    Readability suffers

    Readability is probably worse because ForEach is not as familiar as foreach. Also, the code lines tend to grow long with the first approach and I like my lines of code less than 80 characters.

    ForEach is NOT functional style

    I'd like to stress that I'm still a huge fan of functional style, immutability, composability, first-class functions, etc. The ForEach style described in this blog-post is NOT functional style, although it definitely looks like it.

    1. It is NOT immutable
    2. It is NOT idempotent
    3. It does not chain as Kevin mentions
    4. It is NOT lazy and doesn't have deferred execution like many LINQ operators which are truly functional

    We had a hallway conversation with Chris Smith from F# team about this coding style topic today, and even he (the functional programming guy and a huge F# fan) admitted that sometimes C# should better use C# native constructs instead of borrowing from other (albeit awesome) languages like F#.

    Summary

    So I guess I'm going back to more using good old control flow statements again as they deserve it. They have been here for 30 years for a good reason and I don't think they're going away anytime soon.

  • Kirill Osenkov

    http://twitter.com/KirillOsenkov

    • 2 Comments

    http://twitter.com/KirillOsenkov 

    Goodbye productivity...

  • Kirill Osenkov

    New IDE features in VS 2010

    • 0 Comments

    We have announced a list of new IDE features for managed languages in Visual Studio 2010:

    http://blogs.msdn.com/somasegar/archive/2008/12/19/code-focused-development-in-vs-2010.aspx

  • Kirill Osenkov

    F# No Longer Vaporware

    • 1 Comments

    Chris Smith from the F# team has recently posted some "interesting" news:

    http://blogs.msdn.com/chrsmith/archive/2008/12/10/f-no-longer-vaporware.aspx

  • Kirill Osenkov

    Webcast on Visual Studio Tips &amp; Tricks

    • 5 Comments

    Mike Benkovich from http://benkotips.com and my fellow C# QA team member Eric Maino have talked me into doing a webcast on Visual Studio Tips & Tricks. Mike was the host, and Eric and I were showing VS features that we like and use often in our day-to-day coding.

    Here's a list of tips that Eric and I were showing:

    http://blogs.msdn.com/benko/archive/2008/12/17/visual-studio-tips-tricks-listing.aspx

    And here's the webcast itself:

    http://blogs.msdn.com/benko/archive/2008/12/15/benkotips-webcast-9.aspx

    Hope you like it!

  • Kirill Osenkov

    How to debug crashes and hangs

    • 38 Comments

    At my job on the C# IDE QA team I've learned some useful things about debugging in Visual Studio, which I'd like to summarize in this post. Although the screenshots were made using Visual Studio 2008 SP1, this pretty much applies to other versions of VS as well.

    Rich debugging support

    When you develop your C# application and hit F5, the target process (your program) gets started, and then the Visual Studio process attaches the debugger to the process where your code is running. This way, you can break into the debugger and VS will provide you with all sorts of rich debugging support - current statement highlighting, call stack, watches, locals, immediate window, Edit-and-Continue and so on.

    More importantly, if your application throws an exception or crashes, the debugger will intercept that and provide your with all the information about the exception.

    As a side note, in Visual Studio there is a way to run your code without attaching the debugger - the shortcut is Ctrl+F5. Try throwing an exception in your code when using F5 and Ctrl+F5 to feel the difference.

    throw null;

    By the way, my favorite way to artificially throw exceptions is throw null; I just love the fact that it throws a NullReferenceException because it can't find the exception object and nevertheless does exactly what I want it to do :)

    Crashes and the Watson dialog

    What if a program crashes or throws an exception, which you don't have source code for? Moreover, you didn't start the program using F5, but the operating system launched the process. I remember that before coming to Microsoft, the only thing I could do about some application crashing was to express my disappointment about the fact (usually in Russian). Now I don't feel helpless anymore, because I've learned a couple of tricks. As an example for this we'll crash Visual Studio itself and then debug the crash.

    How to crash Visual Studio?

    Viacheslav Ivanov reported an interesting crashing bug in our language service recently. Save all your work and then paste this code in a C# Console Application and change 'object' to 'int':

    using System;
    
    static class Program
    {
        static void Main()
        {
            ITest<object> test;
            test.Test((object /* and now change the argument type to "int" */ i) => { });
        }
    }
    
    public interface ITest<T> { }
    
    public static class Extensions
    {
        public static void Test<T, I>(this ITest<T> test, Action<ITest<I>> action) { }
    }

    What you will see is the Watson dialog:

    image

    Given this chance, I'd highly recommend everyone to click "Send Error Report" if you ever see this dialog for Visual Studio. Many people "Don't Send" and frankly I don't understand why not. There is no personal information being sent, and we don't want your personal information anyway, honest. What we want is a call-stack and minidump, if possible, so if you want us to fix the product to make it more stable in the future, you will greatly help us if you send us the Error Report. By the way, we usually fix most (if not all) crashes that come in through this dialog, so the chances that we'll fix the crash you report using the dialog are actually pretty high. For example, we've already fixed the bug mentioned above and it works just fine in current builds.

    Attaching a debugger

    So what can you do if an application crashes or hangs? You can attach the debugger to a running process, even if it has already crashed. The code is still being executed (the main thread of the crashed application is usually pumping messages for the error dialog). You can either choose "Debug" on the Watson dialog, or (what I usually do) is start a new instance of Visual Studio myself and attach to the process manually, without dismissing the Watson dialog.

    Note: if the debuggee process crashes and you attach the debugger after the fact, you'll have to manually break into the debugger by pushing the "Pause" button. If the debugger was already attached at the moment of the crash, then it will offer you to break or continue.

    You can attach the Visual Studio debugger to a running process by choosing Tools | Attach To Process (Ctrl+Alt+P):

    image

    You will see the Attach to process dialog:

    image Interesting things to note here are the Attach to: selection. Since Visual Studio is a mixed-mode managed/native application, to get call stacks for both managed and native parts, you'd want to attach to both of them (by clicking Select...):

    image

    If you select both Managed and Native, you'll get richer debugging information about your callstacks - this is recommended.

    Note: if you want to enable mixed-mode debugging (managed+native) for the application that you have source code for, go to project properties of the startup project, and on the Debug tag select "Enable unmanaged code debugging". Then the debugger will automatically attach using mixed-mode.

    Finally, select the process from the list which you'd like to attach to (in our example, it will be devenv.exe) and click Attach. Notice that the process of the debugger itself is not shown in the list, that's why you don't see two devenv.exe in the list.

    Remote Debugging

    What many people don't know is that VS can be used to debug a process running on another machine on the network. To do this, you just need to start the Visual Studio Remote Debugging Monitor on the same machine with the process you want to debug:

    image

    The remote debugging monitor will listen to debugger connections on the other machine and you'll be able to attach the debugger using the Transport and Qualifier fields on the Attach to process dialog:

    image

    You can find more detailed information about Remote Debugging in MSDN and on the internet.

    Set Enable Just My Code to false

    One very important option in Visual Studio is "Enable Just My Code", which is set to true by default. To be able to see more information on the callstacks instead of just "Non-user code", you need to go to Tools | Options and disable this option:

    image

    I usually do this right after I install Visual Studio, so that I can always debug into "not my code".

    Other interesting options on this page are:

    • Enable .NET Framework source stepping - in case you'd like to step into the .NET framework source code
    • Enable Source Server support
    • Step over properties and operators (Managed only) - won't step in to property getters, operators, etc. - this is new in VS 2008 SP1
    • Require source files to exactly match the original version - in case you don't have the source files for the exact .pdb symbol file, but still have a close version of the source code

    Break on first chance exceptions

    One very useful option in the debugger is the ability to break whenever a first-chance exception is being thrown. A first-chance exception is an exception that might be caught by the program itself later in some surrounding catch block. First-chance exceptions are usually non-fatal and handled (or swallowed) by the user, so they might not even be visible to the end user during normal execution. However, if a first-chance exception is not handled in the code and bubbles up to the CLR/OS, then it becomes a crash.

    So, to break on first-chance exceptions, you can go to Debug | Exceptions to invoke the Exceptions dialog:

    image

    Here you can put a checkmark on Common Language Runtime Exceptions for the debugger to break every time a managed exception is thrown. This way you will see more hidden exceptions, some of them originating deep in the .NET framework class library. Sometimes there are so much first-chance exceptions that you can become overwhelmed, but they are incredibly useful to get to the root cause of the problem, because the debugger will show exactly where the exception originated preserving the original surrounding context. Another great advantage of breaking on first-chance exceptions is that the call stack is not unwound yet and the problem frame is still on the stack.

    Debugging tool windows

    OK, so now that we know how to attach a debugger and how to set the debugger options, let's see what happens after we've attached a debugger. For our exercise, you can open two instances of Visual Studio, attach the second instance's debugger to the first one, and then crash the first one using the lambda-expression crash code above. Instead of the Watson dialog on the debuggee process, you will see the following window in the debugger:

    image

    Now you have the chance to break and see where the exception happened. Continue is useful if the exception is actually a first-chance exception and you'd like to pass it on to user code to handle it. Let's hit Break and examine what tool windows are available under debugger.

    Processes window

    All the debugger windows are available from menu Debug | Windows. The Processes window shows the list of processes that the debugger is currently attached to. A nice trick is that you can actually attach to multiple processes at the same time. Then you can use this window to switch the "current" debuggee process and all other tool windows will update to show the content of the "current" process.

    image

    Note: on our team, we use this window a lot, because our tests run out-of-process. Our test process starts Visual Studio in a separate process and automates it using DTE, remoting and other technologies. Once there is a failure in the test, it's useful to attach to both the test process and the Visual Studio process under test. The most fun part is when I was debugging a crash in the debugger, and attached the debugger to the debugger process that is attached to some other process. Now if the debugger debugger crashes on you on the same bug, then you're in trouble ;) Sometimes I definitely should blog more about the fun debugging stories from my day-to-day job. But I digress.

    Threads

    As we all know, processes have multiple threads. If you break into a debuggee process, you will most likely end up with a list of threads that were active at the moment when you did break. Main thread is the green one - this is the UI thread of your application (in our example, Visual Studio). Main thread executes the application message loop, and is pumping the windows messages for the application's UI. If a message box or a dialog is shown, you will see this dialog's message loop on the main thread.

    image

    To switch threads, double-click the thread name that you're interested in. In most of the cases you'll be interested in the main thread. But if you start your own threads, give them a name so that they are easy to find in the threads list.

    Call stack

    Every thread has a call stack. Call stack is probably the most important thing you'd like to know about a crash - what was the sequence of function calls that lead to a crash? If the program is hanging, you'd like to know what function is it hanging in and how did it get there. Oftentimes by just glancing at a callstack you immediately know what's going on. "Is this callstack familiar?" or "Who is on the callstack?" is probably the question we ask most often during the bug triage process.

    Anyway, here's the call stack window:

    image

    In our example we see that the C# language service module is on the stack (.dlls and .exes are called "modules" in the debugging world).

    However instead of function names from cslangsvc.dll we see the addresses of the procedures in memory. This is because the symbols for the cslangsvc.dll module are not loaded. We'll look into how to load symbols in a moment.

    Modules

    The Modules window shows a list of .dlls and .exes loaded into the debuggee process:

    image

    There are multiple ways to load symbols for a given module. You can right-click on a module for a list of options:

    image

    Symbols for modules are stored in .pdb files and are produced with every debug build of the binary. pdb files contain mapping from compiled binaries back to the original source code, so that the debugger can display rich information (function names, source code locations, etc.) for the binary being debugged. Without symbols, debugging is only possible at the assembly level and registers window, you can't map the binaries back to the source code.

    Symbols

    A very useful dialog is the Tools | Options | Debugging | Symbols:

    image

    Here you can set paths where to look for the .pdb files. Normally, the .pdb files will be directly next to the binaries, in which case they are usually found and loaded automatically. Loading symbols takes some time, so Visual Studio supports caching symbol files to some directory. Also, if you don't want all the symbols for all the binaries loaded (it can take a while), you can check the checkbox "Search the above locations only when symbols are loaded manually". Load symbols from Microsoft symbol servers provides symbols for Microsoft products, such as Windows and Visual Studio. You can load symbols from here, or also from the Modules or Call Stack windows, by right-clicking on a module and choosing Load Symbols From. Since we're debugging into Visual Studio, the symbols are located on the Microsoft Symbols servers:

    image

    When we load public symbols, the following little dialog is showing:

    image

    After we've loaded the symbols for cslangsvc.dll we notice that the Call Stack window is now much more informative:

    image

    Given this call stack, anyone of our developers will now easily be able to pinpoint the problem. In our example we see that the problem happens when we try to show the Smart Tag for the Generate Method refactoring:

    image

    As you see, there are more modules for which the symbols haven't been loaded yet. You can load the symbols for those modules by right-clicking their stack frame and choosing Load Symbols From. Loading all the symbols is usually recommended for more detailed information.

    That is why the call stack is so precious during bug reports. To save the call stack, you can Ctrl+A and Ctrl+C to copy all the stack into the clipboard. When you click Send Error Report in the Watson dialog, the call stack is included in the error report.

    Also you see that the call stack is not very useful without the symbols - it's the symbols + the callstack that provide rich information about the crash.

    Minidump

    Another very useful information that you can provide about the crashed process is the memory dump (heap dump, minidump) - this is basically a snapshot of the memory state of the crashed process. To create a minidump, go to Debug | Save Dump As. Visual Studio will offer you to save the dump to a location on disk, and an option to just save the Minidump or Minidump with Heap:

    image

    Minidump with Heap will save more information than just the minidump, but will take a whole lot more disk space (for Visual Studio - possibly hundreds of megabytes - depending on the process working set size during the crash).

    Those are the three components that we usually send to our developers during crash bug reporting:

    1. Call stack
    2. Symbols
    3. Minidump with heap

    In most cases, they are able to understand the problem given this information. A list of repro steps is usually even better, because they can reproduce the problem themselves and enable first-chance exceptions to break early into the problem area.

    Debugging hangs

    If an application hangs, you can attach the debugger to it and hit break to see what thread and what call stack blocks execution. Usually looking at the call stack can give you some clues as to what is hanging the application. Debugging hangs is no different than debugging crashes.

    Microsoft shares customer pain

    Finally, I'd recommend everyone to watch this video:

    Conclusion

    In this post, I've talked about some things worth knowing for effective debugging sessions:

    • Turning off "Enable just my code"
    • Attaching the debugger using Tools | Attach To Process
    • Selecting Managed, Native for mixed-mode debugging or Enable unmanaged code debugging
    • Attaching to multiple processes
    • Selecting processes and threads
    • Breaking on first-chance exceptions using the Debug | Exceptions dialog
    • Picking the right thread
    • Loading symbols
    • Viewing the call stack
    • Saving the minidump file

    Do let me know if you have feedback or corrections about this information.

    kick it on DotNetKicks.com
Page 5 of 7 (154 items) «34567