<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Rick Byers : CLR</title><link>http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx</link><description>Tags: CLR</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Quickly seeing where an exception may land in the debugger</title><link>http://blogs.msdn.com/rmbyers/archive/2009/08/31/quickly-seeing-where-an-exception-may-land-in-the-debugger.aspx</link><pubDate>Tue, 01 Sep 2009 08:08:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9889694</guid><dc:creator>rmbyers</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/9889694.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=9889694</wfw:commentRss><description>&lt;p&gt;A co-worker asked me recently how he could predict where an exception that was about to be thrown would land while debugging a managed application.&amp;#160; The real answer to this question is “you can’t – step into the throw and see”.&amp;#160; The EH system in the CLR has lots of complicated algorithms for determining this, and it needs to interact with other code on the stack (eg. there may be some native code with it’s own SEH filter that can do arbitrary logic).&amp;#160; Luckily, unlike for native debugging, managed debugging can generally “step into” exception throws and reliably land in the handler.&amp;#160; &lt;/p&gt;  &lt;p&gt;But occasionally people still find themselves looking up the callstack, searching the code for ‘try’ blocks that are active.&amp;#160; Surely there’s a way to automate that?&amp;#160; Of course the debugger has all the information necessary to automate that, but unfortunately the VS debugger is not easily extensible in this way, so there’s not a lot you can do from the debugger process.&amp;#160; However, as usual, func-eval offers a nice work-around for the lack of easy extensibility.&amp;#160; Using the technique in my “&lt;a href="http://blogs.msdn.com/rmbyers/archive/2005/04/30/413752.aspx"&gt;Run-time exception checking&lt;/a&gt;” post, we can func-eval code which gets the EH handler info for the current stack and displays it nicely in the watch window.&amp;#160; I’ve posted a sample (source and binary) which does that &lt;a href="http://code.msdn.microsoft.com/ExceptionHandlerInfo"&gt;here&lt;/a&gt;.&amp;#160; To use it, download &lt;a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=ExceptionHandlerInfo&amp;amp;DownloadId=7093"&gt;ExceptionHandlerInfo.dll&lt;/a&gt;, and then while stopped in the debugger enter Assembly.LoadFrom(@&amp;quot;c:\mypath\ExceptionHandlerInfo.dll&amp;quot;) into the immediate window to get it loaded into the debuggee process.&amp;#160; Now, whenever you want to quickly see what handlers are active on the current stack, you can enter “Microsoft.Samples.ExceptionHandlerInfo.EHInfoCollector.GetActiveEHClauses()” into the watch window:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Quicklyseeingwhereanexceptionmaylandinth_1329B/GetActiveEHClauses1_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="GetActiveEHClauses1" border="0" alt="GetActiveEHClauses1" src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Quicklyseeingwhereanexceptionmaylandinth_1329B/GetActiveEHClauses1_thumb.png" width="783" height="168" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;In this example, we can see that there is first a “catch System.ArgumentException” at Program.cs line 35 in method '”Program.Catcher” which is the 2nd (#1) frame on the current stack.&amp;#160; Above that on the stack there is a “catch Exception” and a “Finally” block in the “Program.Main” method, and then a “Finally” block inside the VS hosting process code (for which we don’t have PDBs to provide a source location).&lt;/p&gt;  &lt;p&gt;You can drill info EHInfo objects further if you want more details on a particular frame:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Quicklyseeingwhereanexceptionmaylandinth_1329B/GetActiveEHClauses2_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="GetActiveEHClauses2" border="0" alt="GetActiveEHClauses2" src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Quicklyseeingwhereanexceptionmaylandinth_1329B/GetActiveEHClauses2_thumb.png" width="781" height="406" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;And if you want to automate scanning all the active EH clauses for the one most likely to catch the currently active exception (eg. when stopping on first-chance exceptions), you can enter “Microsoft.Samples.ExceptionHandlerInfo.EHInfoCollector.GuessCatchHander($exception.GetType())”:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Quicklyseeingwhereanexceptionmaylandinth_1329B/GuessCatchHandler_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="GuessCatchHandler" border="0" alt="GuessCatchHandler" src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Quicklyseeingwhereanexceptionmaylandinth_1329B/GuessCatchHandler_thumb.png" width="783" height="160" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Now someone just needs to integrate this with a VS macro so I can jump to the most likely catcher with a single keypress ;-)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9889694" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>New interviews with my CLR team members up on Channel9</title><link>http://blogs.msdn.com/rmbyers/archive/2009/06/08/new-interviews-with-my-clr-team-members-up-on-channel9.aspx</link><pubDate>Tue, 09 Jun 2009 07:19:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9712626</guid><dc:creator>rmbyers</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/9712626.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=9712626</wfw:commentRss><description>&lt;P&gt;There are a bunch of great new &lt;A href="http://channel9.msdn.com/tags/CLR+4/" mce_href="http://channel9.msdn.com/tags/CLR+4/"&gt;CLR v4-related video interviews&lt;/A&gt;&amp;nbsp;up on Channel9.&amp;nbsp; In particular:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://channel9.msdn.com/posts/Charles/CLR-4-Debugging-and-Profiling-Enhancements/" mce_href="http://channel9.msdn.com/posts/Charles/CLR-4-Debugging-and-Profiling-Enhancements/"&gt;Jon, Thomas and Dave from my team&lt;/A&gt; (CLR diagnostics) discuss the advancements in debugging and profiling APIs in v4&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://channel9.msdn.com/shows/Going+Deep/CLR-4-Side-by-Side-In-Process-What-How-Why/" mce_href="http://channel9.msdn.com/shows/Going+Deep/CLR-4-Side-by-Side-In-Process-What-How-Why/"&gt;Simon and I&lt;/A&gt; discuss in-process SxS (ability to have multiple CLRs loaded in the same process).&amp;nbsp; You may have noticed the lack of diagnostics blog entries from me lately - that's because I've mostly been spending my time helping out with this important feature.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;There are a bunch of other ones that look good (eg. "Type equivalence" and "No-PIAs" are closely related and an interesting discussion), but I haven't gotten a chance to watch them yet.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9712626" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category></item><item><title>AnyCPU Exes are usually more trouble than they're worth</title><link>http://blogs.msdn.com/rmbyers/archive/2009/06/08/anycpu-exes-are-usually-more-trouble-then-they-re-worth.aspx</link><pubDate>Tue, 09 Jun 2009 07:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9712624</guid><dc:creator>rmbyers</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/9712624.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=9712624</wfw:commentRss><description>&lt;P&gt;Over the past few months I've had some interesting debates with folks here (and some customers) about the cost/benefit trade-off of "AnyCPU" (architecture-neutral)&amp;nbsp;managed EXEs.&amp;nbsp; I think we've converged on a consensus that most of the time they're not what you want and so shouldn't be the default in Visual Studio.&amp;nbsp; I suspect this topic may interest (and even shock) some folks, so I thought I'd share the rationale with you here.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Background - .NET and 64-bit&lt;BR&gt;&lt;/STRONG&gt;With the introduction of Win64 (64-bit versions of Windows), PE files (EXEs and DLLs) can be marked either as 32-bit OR 64-bit.&amp;nbsp; When a 32-bit EXE is launched on Win64, it runs in "the WOW" (Windows-32 on Windows-64) to present an illusion of a 32-bit operating system to the process.&amp;nbsp; Generally only 32-bit DLLs can be loaded into a 32-bit process, and only 64-bit DLLs can be loaded into a 64-bit process.&amp;nbsp; When the CLR added 64-bit support in version 2.0, we had an interesting decision to make.&amp;nbsp; Should we mark our binaries as 32-bit or 64-bit by default?&amp;nbsp; Techncally managed binaries had no hard CPU dependency, so they could be either (actually there is a small loader thunk, but that's unused on any newer OS including all the 64-bit ones since the OS loader knows about managed EXEs explicitly).&amp;nbsp; Since we wanted people to be able to write .NET libraries that they could re-use from both 32-bit and 64-bit processes, we worked with Windows to extend the OS loader support to enable architecture-neutral ("AnyCPU") PE files.&lt;/P&gt;
&lt;P&gt;Managed architecture-neutral DLLs are fairly straight-forward - they can be loaded into either 32-bit or 64-bit processes, and the (32-bit or 64-bit) CLR in the process will do the right thing with them.&amp;nbsp; AnyCPU EXEs are a little more complicated since the OS loader needs to decide how to initialze the process. On 64-bit OSes they are run as 64-bit processes (unless the 'ldr64' master OS switch says otherwise), and on 32-bit OSes they are run as 32-bit processes.&amp;nbsp; In Visual Studio 2008, AnyCPU is the default platform for C# and VB projects.&amp;nbsp; This means that by default, applications you compile will run in 64-bit processes on 64-bit OSes and 32-bit processes on 32-bit OSes.&amp;nbsp; This is fine and does often work alright, but there are a number of minor downsides.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The costs of architecture-neutral EXEs&lt;/STRONG&gt;&lt;BR&gt;There are a number of reasons to think that AnyCPU should not be the default for EXEs.&amp;nbsp; Don't get me wrong, 64-bit hardware and OSes are definitely the way to go (in fact all 4 of my development machines have 64-bit OSes on them - I stopped bothering to install 32-bit OSes years ago).&amp;nbsp; But that doesn't necessarily mean that most processes should be 64-bit.&amp;nbsp; Here's the list I've been using in our discussions to justify making x86 the default for EXE projects in Visual Studio:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Running in two very different modes increases product complexity and the cost of testing&lt;BR&gt;Often people don't realize the implications on native-interop of architecture-neutral assemblies.&amp;nbsp; It means you need to ensure that equivalent 32-bit and 64-bit versions of the native DLLs you depend on are available, and (most significantly) the appropriate one is selected automatically.&amp;nbsp; This is fairly easy when calling OS APIs due to the OS re-mapping of c:\windows\system32 to c:\windows\syswow64 when running in the WOW and extensive testing the OS team does.&amp;nbsp; But many people who ship native DLLs alongside their managed app get this wrong at first and are surprised then their application blows up on 64-bit systems with an exception about their 32-bit DLL being in a bad format.&amp;nbsp; Also, although it's much rarer than for native-code, pointer-size bugs&amp;nbsp;can still manifest in .NET (eg. assuming IntPtr is the same as Int32, or incorrect marshalling declarations when interopping with native code).&lt;BR&gt;Also, in addition to the rules you need to know to follow, there's just the issue that you've now really got twice as much code to test.&amp;nbsp; Eg., there could easily be (and certainly have been many) CLR bugs that reproduce only on one architecture of the CLR, and this applies all the way across the stack (from OS, framework, 3rd-party libraries, to your code).&amp;nbsp; Of course in an ideal world everyone has done a great job testing both 32-bit and 64-bit and you won't see any differences, but in practice for any large application that tends not to be the case, and (at Microsoft at least) we end up duplicating our entire test system for 32 and 64-bit and paying a significant ongoing cost to testing and supporting all platforms.&lt;BR&gt;[Edit: Rico - of CLR and VS performance architect fame - just posted &lt;A href="http://blogs.msdn.com/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version.aspx" mce_href="http://blogs.msdn.com/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version.aspx"&gt;a great blog entry&lt;/A&gt; on why Visual Studio will not be a pure 64-bit application anytmie soon]&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;32-bit tends to be faster anyway&lt;BR&gt;When an application can run fine either in 32-bit or 64-bit mode, the 32-bit mode tends to be a little faster.&amp;nbsp; Larger pointers means more memory and cache consumption, and the number of bytes of CPU cache available is the same for both 32-bit and 64-bit processes.&amp;nbsp; Of course the WOW layer does add some overhead, but the performance numbers I've seen indicate that in most real-world scenarios running in the WOW is faster than running as a native 64-bit process&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Some features aren't avaiable in 64-bit&lt;BR&gt;Although we all want to have perfect parity between 32-bit and 64-bit, the reality is that we're not quite there yet.&amp;nbsp; CLR v2 only supported mixed-mode debugging on x86, and although we've finally added x64 support in CLR V4, edit-and-continue still doesn't support x64.&amp;nbsp; On the CLR team, we consider x64 to be a first-class citizen whenever we add new functionality, but the reality is that we've got a complicated code-base (eg. completely separate 32-bit and 64-bit JIT compilers) and we sometimes have to make trade-offs (for example, adding 64-bit EnC would have been a very significant cost to the JIT team, and we decided that their time was better spent on higher priority features).&amp;nbsp; There are other cool features outside of the CLR that are also specific to x86 - like historical debugging in VS 2010.&amp;nbsp; Complicating matters here is that we haven't always done a great job with the error messages, and so sometimes people "upgrade" to a 64-bit OS and are then disgusted to see that some of their features no longer appear to work (without realizing that if they just re-targetted the WOW they'd work fine).&amp;nbsp; For example, the EnC error in VS isn't very clear ("Changes to 64-bit applications are not allowed"), and has lead to &lt;A href="http://social.msdn.microsoft.com/Forums/en-US/csharpide/thread/132512e0-bd07-49c1-9837-121a4151e226/" mce_href="http://social.msdn.microsoft.com/Forums/en-US/csharpide/thread/132512e0-bd07-49c1-9837-121a4151e226/"&gt;some confusion in practice&lt;/A&gt;.&amp;nbsp; I believe we're doing the right thing in VS2010 and fixing that dialog to make it clear that switching your project to x86 can resolve the issue, but still there's no getting back the time people have wasted on errors like this.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;STRONG&gt;When do 64-bit processes make sense?&lt;BR&gt;&lt;/STRONG&gt;The biggest benefit of 64-bit processes is obivously the increased address-space.&amp;nbsp; Many programs are bumping up against the 2GB limit of traditional 32-bit processes (even though they may not be using anywhere near 2GB of RAM).&amp;nbsp; The first thing that should usually be done to such programs is to have them opt-into 4GB mode so that they can get a full 4GB of address space when running in the WOW on a 64-bit OS.&amp;nbsp; If more address space would be useful, than sometimes the right thing to do is to decide to target JUST x64 and avoid the cost of supporting two platforms (Exchange Server has done this for example).&amp;nbsp; But often the right trade-off is to support both 32-bit and 64-bit processes, so that you can still run on 32-bit OSes, but take advantage of the large address space when running on 64-bit OSes.&amp;nbsp; &lt;BR&gt;&lt;BR&gt;This is where architecture-neutral assemblies make a lot of sense.&amp;nbsp; If you're a library vendor, then building as AnyCPU and testing on all supported architectures absolutely makes sense.&amp;nbsp; If you are producing an application EXE and have reason to believe your application may need more than 4GB of address space, then switching to AnyCPU may be a good idea.&amp;nbsp; But, as for native, really needing this much address space is still pretty rare and usually only necessary for large complex applications, and so opting-in to AnyCPU should really not be a burden.&amp;nbsp; You've got to think about what you want your testing strategy to be anyway, so making this step explicit seems to make sense.&lt;/P&gt;
&lt;P&gt;Another argument for AnyCPU being the default which I think deserves serious thought is the impact on the Windows ecosystem and desire to move to a pure 64-bit world someday.&amp;nbsp; No doubt the WOW adds extra complexity and confusion and it would be great to just kill it as quickly as we can.&amp;nbsp; I definitely agree with that sentiment, and we should work to get to that place.&amp;nbsp; But realistically, we're a long way from being able to seriously consider killing the WOW from Client OSes (it is already optional on Server Core - but how many EXE projects are really server apps?).&amp;nbsp; Here are some things that need to happen before we can seriously consider killing the WOW: Windows needs to stop shipping new 32-bit-only client OSes, most new native applications need to fully support 64-bit, all popular existing apps need to move to 64-bit (including VS), etc.&amp;nbsp; I'm sure we'll get there some day (as we did with the 16-bit to 32-bit transition), but I don't think defaulting to x86 in Visual Studio is going to be a major barrier here.&amp;nbsp; When it starts looking like killing the WOW may be a feasible option in the near-future, then perhaps we should probably just switch the default to be x64-only, and let people opt-in to supporting 'legacy' 32-bit platforms.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;So how is Visual Studio 2010 and .NET 4.0 changing?&lt;BR&gt;&lt;/STRONG&gt;We are not changing anything here in the CLR or compilers - they continue to support both modes.&amp;nbsp; However, after discussing these issues, VS project system team has agreed to make EXE projects default to the x86 platform in VS 2010.&amp;nbsp; Unfortunately there is a bug in Beta1 where ALL managed project types default to x86 (I take the blame for this - I didn't think to check DLL projects when validating the changes were in).&amp;nbsp; AnyCPU is still incredibly valuable for DLLs (you may not always know what processes it will be loaded into), and since it just enables a DLL to be used in more places without actually affecting the bitness of the process, there isn't sufficient justification to disable AnyCPU by default.&amp;nbsp; This bug has been fixed, and so the plan is to ship Beta2 with just the EXE projects defaulting to x86, and all DLL projects remaining as AnyCPU.&lt;/P&gt;
&lt;P&gt;That said, there's still time to get customer feedback and so this could change for VS2010 RTM.&amp;nbsp; We've already heard a lot of surprised reactions where people seem to think we're treating x64 as second-class, or otherwise resisting the natural evolution to 64-bit systems.&amp;nbsp; Many people have mentioned that 32-bit hardware and 32-bit OSes are quickly becoming a thing of the past.&amp;nbsp; I agree completely and this is a good trend, but it's completely orthogonal.&amp;nbsp; 64-bit hardware and OSes give us the ability to run processes with 64-bit address spaces, but they by no means make using them a requirement or necessarily even preferable to using the WOW.&amp;nbsp; The Windows folks did such a good job building the WOW, and the CPU designers did a good job supporting 32-bit modes (for x64 at least, ia64 is a different story), so&amp;nbsp;there aren't a lot of downsides to relying on them.&amp;nbsp; Someday I'm sure we'll decide the WOW has outlived it's useful lifetime and Windows should kill it rather than maintain it, but I'm sure that day is a LONG way off (eg. when did Windows finally remove support for 16-bit processes, and did anyone really notice?).&amp;nbsp; &lt;BR&gt;&lt;BR&gt;When I actually get into debating this issue on it's merrits, almost everyone I've talked to has agreed that making x86 the default seems to be the best choice - at least for the next several years.&amp;nbsp; This, by no means signifies decreased support for 64-bit OSes and frameworks.&amp;nbsp; I can tell you that most CLR developers work almost exclusiviely on x64 OSes, and do much of their testing and development with 64-bit processes.&amp;nbsp; Our testing (like most teams at Microsoft) treats x86 and x64 as first-class and generally equal-priority (except for products like Silverlight of course that are still x86-only).&amp;nbsp; But when we put ourselves in the shoes of our users and study this issue on it's merrits, it just makes practical sense for x86 to be the default for EXE projects.&lt;/P&gt;
&lt;P&gt;Let me know if you agree or disagree.&amp;nbsp; Regardless, I hope you enjoy using VS2010 - it's really shaping up to be a great release!&lt;/P&gt;
&lt;P mce_keep="true"&gt;[Edit - added section about helping the ecosystem move to all 64-bit]&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9712624" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Getting good dumps when an exception is thrown</title><link>http://blogs.msdn.com/rmbyers/archive/2008/12/22/getting-good-dumps-when-an-exception-is-thrown.aspx</link><pubDate>Tue, 23 Dec 2008 09:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9249385</guid><dc:creator>rmbyers</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/9249385.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=9249385</wfw:commentRss><description>&lt;p&gt;Often, when an unexpected exception occurs in production code, applications want to generate (and potentially report) some sort of diagnostics information.&amp;#160; Sometimes people just want to write to a log file (and perhaps pop some error dialog) for support purposes, but more sophisticated applications will want to have a mechanism to save a minidump of the crash (and perhaps report it back to the author of the software) so their developers can debug the problem.&amp;#160; &lt;a class="" href="http://msdn.microsoft.com/en-us/isv/bb190483.aspx" mce_href="http://msdn.microsoft.com/en-us/isv/bb190483.aspx"&gt;Windows Error Reporting&lt;/a&gt; is usually the best way to do this (the CLR v2 and above &lt;a class="" href="http://msdn.microsoft.com/en-us/library/bb219076.aspx#MicrosoftErrorReporting_ManagedCode" mce_href="http://msdn.microsoft.com/en-us/library/bb219076.aspx#MicrosoftErrorReporting_ManagedCode"&gt;integrates with WER&lt;/a&gt; for all managed apps), but people also like to build their own custom solutions.&amp;#160; By the way, if you want to build your own error-reporting mechanism that captures dump files, I suggest you use a helper process to suspend all your threads and call MiniDumpWriteDump, rather than calling it directly in-process (see &lt;a href="http://www.eggheadcafe.com/software/aspnet/29825284/loader-lock-deadlock-in-m.aspx"&gt;this discussion&lt;/a&gt; for example).&lt;/p&gt;  &lt;p&gt;As a very simple example, you may want to use the FailFast API to say &amp;quot;exceptions should never escape here, if it does present an error to the user and let them report the problem back through WER&amp;quot;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;try
&lt;/span&gt;{
    MyCode();
}
&lt;span style="color: blue"&gt;catch &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Exception &lt;/span&gt;ex)
{
    &lt;span style="color: green"&gt;// We don't expect any exceptions - generate an error-report if we see one
    &lt;/span&gt;System.&lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.FailFast(&lt;span style="color: #a31515"&gt;&amp;quot;Unexpected exception: &amp;quot; &lt;/span&gt;+ ex.Message);
}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Unfortunately, this won’t give you a very useful dump in your error-report.&amp;#160; The problem is that by the time the catch block has been started, the stack frames showing how the exception occurred are no longer available (see below for details).&amp;#160; Managed exceptions are built on &lt;a href="http://www.microsoft.com/msj/0197/exception/exception.aspx"&gt;Windows Structured Exception Handling&lt;/a&gt;, and so have the same two-pass model.&amp;#160; ‘catch’ blocks are executed on the second pass, but really what we want here is to generate our error-report on the first-pass (before EBP gets reset).&amp;#160; You are probably used to seeing this when debugging your code.&amp;#160; If you really want to see what caused an exception, you have to tell Visual Studio to &lt;a href="http://msdn.microsoft.com/en-us/library/h22dk1y6.aspx"&gt;stop on first-chance exceptions&lt;/a&gt; – by the time you stop in the catch block, the code that threw the exception is no longer visible on the callstack:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Gettinggooddumpswhenanexceptionisthrown_141E6/image_2.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="316" alt="image" src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Gettinggooddumpswhenanexceptionisthrown_141E6/image_thumb.png" width="607" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luckily the CLR provides a way to do this called managed exception filters.&amp;#160; Unfortunately C# doesn’t expose a way to use them.&amp;#160; The simplest way to use a filter from C# code is to write a simple helper function in VB.Net.&amp;#160; The ‘When’ portion of a ‘Catch’ clause in VB.Net is an exception filter.&amp;#160; Here’s a simple helper I wrote for this that I can easily call from C#:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;ExceptionUtils
    &lt;span style="color: blue"&gt;Public Shared Sub &lt;/span&gt;Filter(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;body &lt;span style="color: blue"&gt;As &lt;/span&gt;Action, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;filter &lt;span style="color: blue"&gt;As &lt;/span&gt;Func(&lt;span style="color: blue"&gt;Of &lt;/span&gt;Exception, &lt;span style="color: blue"&gt;Boolean&lt;/span&gt;), &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;handler &lt;span style="color: blue"&gt;As &lt;/span&gt;Action(&lt;span style="color: blue"&gt;Of &lt;/span&gt;Exception))
        &lt;span style="color: blue"&gt;Try
            &lt;/span&gt;body()
        &lt;span style="color: blue"&gt;Catch &lt;/span&gt;ex &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception &lt;span style="color: blue"&gt;When &lt;/span&gt;filter(ex)
            handler(ex)
        &lt;span style="color: blue"&gt;End Try
    End Sub
End Class&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now I can re-write my code that triggers error-reporting on exceptions as follows (referencing the VB assembly with the above code):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;ExceptionUtils&lt;/span&gt;.Filter(() =&amp;gt;
{
    &lt;span style="color: green"&gt;// This is the body of the 'try'
    &lt;/span&gt;MyCode();
}, (ex) =&amp;gt;
{
    &lt;span style="color: green"&gt;// This is the body of the filter
    &lt;/span&gt;System.&lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.FailFast(&lt;span style="color: #a31515"&gt;&amp;quot;Unexpected exception: &amp;quot; &lt;/span&gt;+ ex.Message);
    &lt;span style="color: blue"&gt;return false&lt;/span&gt;; &lt;span style="color: green"&gt;// don't catch - this code isn't reached
&lt;/span&gt;}, &lt;span style="color: blue"&gt;null&lt;/span&gt;); &lt;span style="color: green"&gt;// no catch block needed&lt;/span&gt;&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;Now, running under the debugger I can see the original call-stack, and even inspect locals/args on it (note the ‘Throw’ frame in the callstack, and the visible arg value for a – I can also click on this frame and poke around as normal):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Gettinggooddumpswhenanexceptionisthrown_141E6/image_4.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="470" alt="image" src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Gettinggooddumpswhenanexceptionisthrown_141E6/image_thumb_1.png" width="783" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So that’s basically it.&amp;#160; Now debugging at the point of the FailFast (whether live, or with a dump file) will let you see all the data on the stack leading up to the cause of the exception.&amp;#160; Note that if exceptions are thrown and &lt;em&gt;caught within&lt;/em&gt; the body they don’t trigger the filter, the filter is just like a catch block in that it cares about exceptions that “reach” it – which is usually what you want (eg. it’s not normally any of your concern if the implementation of some external API you call happens to throw and catch an exception – as long as it doesn’t propagate back to your code).&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h2&gt;Additional Details&lt;/h2&gt;

&lt;p&gt;It might be a bit of a pain to have to deploy this extra assembly with your application, but there are other options for using an exception filter in your C# app:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Statically link the C# and VB code together into a single (single-file) assembly (eg. using &lt;a href="http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlesslyWithILMergeAndMSBuild.aspx"&gt;ILMerge&lt;/a&gt;, Link.EXE, or a &lt;a href="http://blogs.msdn.com/greggm/archive/2006/03/23/559155.aspx"&gt;ILDasm/ILAsm round-trip&lt;/a&gt;)&lt;/li&gt;

  &lt;li&gt;Use a tool to re-write your assembly after it’s built to inject the filter.&amp;#160; Gregg on the VS debugger team &lt;a href="http://blogs.msdn.com/greggm/archive/2008/04/21/exception-filter-inject.aspx"&gt;posted such a tool awhile back&lt;/a&gt;.&lt;/li&gt;

  &lt;li&gt;Use Reflection.Emit to dynamically generate the IL code for the filter at run-time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also, one note about using FailFast with managed error-reporting.&amp;#160; Error-reports are grouped by their ‘bucket parameters’.&amp;#160; The buckets generated for System.Environment.FailFast(string) are always the same for any given call-site (basically just the address of the call, and a the string ‘FatalError’ for the exception type.&amp;#160; Ideally what you’d like to do here is use the buckets for the original exception (so that two different exceptions that trigger the same call to FailFast will show up as two different problems).&amp;#160; We’ve added a FailFast overload that takes an Exception object in .NET 4.0 that does this.&lt;/p&gt;

&lt;p&gt;All I’ve talked about so far are simple single exceptions.&amp;#160; Exceptions can also be caught and re-thrown ('”throw;” in C#) or wrapped in an outer exception which is thrown (“nested exceptions”).&amp;#160; Unfortunately if that happens within the body you pass to ExceptionUtils.Filter, by the time the filter is invoked, the first exception has already been thrown and caught and so the stack you see is at the point of rethrow.&amp;#160; There’s no good way that I’m aware of to get the stack from the original throw point in this case (although it’s something I’d like to get added to the CLR in a future version).&amp;#160; This is particularly troublesome when using .NET APIs that catch-and-rethrow like Reflection (which wraps all exceptions in a TargetInvocationException).&amp;#160; The best thing I can suggest is to put filters inside any such point, so you filter sees the exception before it’s caught.&amp;#160; &lt;/p&gt;

&lt;p&gt;If you want to be really hard-core about exceptions, you could use some sort of exception monitoring solution that notices as soon as an exception is thrown.&amp;#160; For example, you could generate a dump from a &lt;a href="http://msdn.microsoft.com/en-us/library/ms679274.aspx"&gt;vectored exception handler&lt;/a&gt;, but you won’t have access to the managed System.Exception object here.&amp;#160; Better yet, you could write a tool that uses the debugging APIs to watch for first-chance exceptions and log details about them (perhaps including dump files) such as &lt;a href="http://blogs.msdn.com/jmstall/archive/2005/07/28/print_exceptions.aspx"&gt;Mike Stall’s MDbg exception harness&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Above I said that in a catch block the frames leading up to the throw are no longer available on the stack.&amp;#160; Technically, they’re still on the stack (the stack isn’t really “unwound” until you leave the catch block), but &lt;a href="http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx"&gt;the frame pointer has been reset&lt;/a&gt; to point to the frame of the catch block (so that locals are available, etc.).&amp;#160; This is true for native code as well, but powerful low-level debuggers like WinDbg allow you to switch the current context to that where an exception was thrown (.cxr command in windbg) if you have the CONTEXT pointer (which might even be saved into the dump for you – which you can access with .ecxr).&amp;#160; An additional complication with managed code is that once the frame pointer has been reset, we no longer report any “roots”on the stack to the GC, so if a collection occurs there may actually be garbage pointers on (or available from) that masked portion of the stack.&amp;#160; So it’s not a simple feature to expose some way to see the callstack starting from the throw site (unless we disabled inspection all locals and arguments, or allowed it to fail unpredictably).&amp;#160; We’ve toyed with ideas for relaxing this in the CLR, but there won’t be any improvements here in CLR v4.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;At the PDC this year I learned that this general class of problems (error reporting / logging in the face of exceptions) is something that many customers are very interested in.&amp;#160; I don’t think we’ve got a ton of great documentation on this today.&amp;#160; Going forward, you should expect to see more documentation, blog entries and new features from the CLR team in this area.&amp;#160; Feel free to let me know if there’s anything in particular you’d like to know more about.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9249385" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/ICorDebug/default.aspx">ICorDebug</category></item><item><title>CLR 4.0 advancements in diagnostics</title><link>http://blogs.msdn.com/rmbyers/archive/2008/10/30/clr-4-0-advancements-in-diagnostics.aspx</link><pubDate>Fri, 31 Oct 2008 00:30:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9016854</guid><dc:creator>rmbyers</dc:creator><slash:comments>16</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/9016854.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=9016854</wfw:commentRss><description>&lt;P&gt;We announced at PDC today that we're making some significant advances in diagnostics tool support for CLR v4!&amp;nbsp; In particular, we've been investing heavily in improving our support for production diagnostics scenarios over the past couple years.&amp;nbsp; I'm excited that we're finally able to&amp;nbsp;start talking about it!&lt;/P&gt;
&lt;P&gt;Here's a quick list of some of the things we're doing - stay tuned here,&amp;nbsp;&lt;A class="" href="http://blogs.msdn.com/davbr/" mce_href="http://blogs.msdn.com/davbr/"&gt;Dave's blog&lt;/A&gt; and &lt;A class="" href="http://blogs.msdn.com/jmstall" mce_href="http://blogs.msdn.com/jmstall"&gt;Mike's blog&lt;/A&gt; for more details.&amp;nbsp; Also feel free to ask questions about our strategy and specific plans for new features on &lt;A class="" href="http://social.msdn.microsoft.com/Forums/en-US/netfxtoolsdev/threads/" mce_href="http://social.msdn.microsoft.com/Forums/en-US/netfxtoolsdev/threads/"&gt;our forum&lt;/A&gt;&amp;nbsp;(of course we still have a few things we're not ready to talk about yet).&amp;nbsp; Of course, all of the features below are only available when targetting a process that is running inside version 4 of the CLR.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Managed dump debugging&lt;BR&gt;&lt;/STRONG&gt;Finally you'll be able to open crash dump files in Visual Studio and see managed state (stacks, locals, etc.) without using SOS.&amp;nbsp; The key scenario we want to enable here is taking a dump of an app/server in production (perhaps in an automated way like Windows Error Reporting) and opening that dump in Visual Studio on another machine at some point in the future.&amp;nbsp;&amp;nbsp;We have a big piece of this working in the VS 2010 CTP, but we still have some work to do before beta (eg. the CTP supports&amp;nbsp;dumps with full heap memory).&amp;nbsp; The experience in VS is very much like being stopped at a breakpoint in a live process, except you can't say "go".&amp;nbsp; Of course production code tends to&amp;nbsp;have JIT-optimizations enabled, so the normal caveats about debugging optimized code&amp;nbsp;apply here too (eg. may not see all locals).&amp;nbsp;&amp;nbsp;Also, you can't evaluate arbitrary expressions since there is no target process to call functions in (but we have some ideas for how we might compensate for this).&amp;nbsp; But despite the caveats, this is still a huge feature that should really help improve production diagnostics scenarios.&amp;nbsp; This work is actually the main visible piece of a much larger "out-of-process debugging" re-architecture we've been working on for years.&amp;nbsp; This re-arch deserves a post of it's own so stay tuned.&lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Profiler attach (and detach) for memory diagnostics and sampling&lt;BR&gt;&lt;/STRONG&gt;One of the most common feature requests we hear from profiling tools is to be able to attach to a target process (today you have to set some environment variables at process start which cause your profiler to be loaded).&amp;nbsp; Before you get too excited - this doesn't have everything you want.&amp;nbsp; In particular, the CLR still doesn't have the ability to change the code of a method once it's been JIT-compiled (EnC is a &lt;EM&gt;very&lt;/EM&gt; special case - not really applicable here).&amp;nbsp; This means that IL instrumentation isn't available on attach, as well as a few other features (like object allocated callbacks).&amp;nbsp; But basic memory diagnostics scenarios where the profiler inspects the heap, and simple sampling-based CPU profiling&amp;nbsp;will now work on attach.&amp;nbsp; We anticipate this will be useful in production scenarios - you can walk up to a server behaving badly and attach a profiler, collect some data, and detach - leaving the process in basically the same state it was before you attached.&lt;BR&gt;[Update: See Dave's blog entry &lt;A class="" href="http://blogs.msdn.com/davbr/archive/2008/11/10/new-stuff-in-profiling-api-for-upcoming-clr-4-0.aspx" mce_href="http://blogs.msdn.com/davbr/archive/2008/11/10/new-stuff-in-profiling-api-for-upcoming-clr-4-0.aspx"&gt;here&lt;/A&gt; for additional details on profiling API improvements]&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Registry-free profiler activation&lt;BR&gt;&lt;/STRONG&gt;One major impediment to the sort of production scenario I described above is that today you have to register your profiler in the registry.&amp;nbsp; In many production scenarios, making some change to the machine-wide system registry is very unappealing (will the dev remember to undo the change when he's done with the server, etc?).&amp;nbsp; So to really enable production scenarios, we've also supplied a mechanism for running a process under a managed profiler (or attaching) without having to make any changes to the registry.&lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;x64 mixed-mode debugging&lt;BR&gt;&lt;/STRONG&gt;This isn't really a production diagnostics scenario (although you can do x64 mixed-mode dump debugging), but is one of the main debugging feature requests we've gotten.&amp;nbsp; With this feature, "mixed-mode" (native+managed) debugging will work for x64 processes in basically the same way&amp;nbsp;it works for&amp;nbsp;x86 today.&amp;nbsp; &lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;lock inspection&lt;/STRONG&gt;&lt;BR&gt;We're adding some simple APIs to ICorDebug which allow you to explore managed locks (Monitors).&amp;nbsp; For example, if a thread is blocked waiting for a lock, you can find what other thread is currently holding the lock (and if there is a time-out).&lt;BR&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Corrupted-state exceptions&lt;BR&gt;&lt;/STRONG&gt;This feature doesn't come from our team (it's part of the core exception-handling sub-system in the CLR), but in my opinion it's a huge improvement for diagnostics scenarios.&amp;nbsp; Basically it means that "bad" exceptions (like access violations) that propagate up the stack into manage code no longer (by default) get converted into normal .NET exceptions (System.AccessViolation) which you can accidentally catch in a "catch(Exception)" clause.&amp;nbsp; Basically, haivng a catch(Exception) which swallows AVs coming from native code is a bad thing because you're unlikely to be able to reason about the consistency of your process after the AV.&amp;nbsp; The default behavior for such "corrupted-state exceptions" is now to fail-fast and send an error-report (just like in normal C++ programming).&amp;nbsp; Of course, you can override this if you REALLY need to catch such an exception.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;That's the overview of the main CLR v4 features that affect diagnostics.&amp;nbsp; Of course there are also lots of other great things coming in CLR v4 and the rest of .NET Fx 4.0.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9016854" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/ICorDebug/default.aspx">ICorDebug</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/ICorProfile/default.aspx">ICorProfile</category></item><item><title>Func-eval can fail while stopped in a non-optimized managed method that pushes more than 256 argument bytes </title><link>http://blogs.msdn.com/rmbyers/archive/2008/08/16/Func_2D00_eval-can-fail-while-stopped-in-a-non_2D00_optimized-managed-method-that-pushes-more-than-256-argument-bytes-.aspx</link><pubDate>Sun, 17 Aug 2008 02:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8872792</guid><dc:creator>rmbyers</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/8872792.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=8872792</wfw:commentRss><description>&lt;P&gt;In &lt;A href="http://blogs.msdn.com/jmstall/archive/2005/11/15/funceval-rules.aspx" mce_href="http://blogs.msdn.com/jmstall/archive/2005/11/15/funceval-rules.aspx"&gt;this blog entry&lt;/A&gt;, Mike describes that func-eval will fail when not a GC-safe point.&amp;nbsp; In VS this results in the error "Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible, possibly because the code is optimized".&amp;nbsp; Typically non-optimized (debuggable) managed code is compiled as "fully-interruptible" which means every point is a GC-safe point.&amp;nbsp; However, occasionally I hear complaints that VS is giving the error even when in non-optimized code.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;In CLR 2.0, the x86 JIT has a limitiation where it will fall back to partially-interruptible code if more than 256 bytes of arguments are pushed onto the stack (which is normally very rare).&amp;nbsp; [Update: corrected claim that the limitation was introduced in 2.0, .NET 1.1 actually had an even smaller&amp;nbsp;limit of 128 bytes].&amp;nbsp; For example, the code below passes two 128 byte structures by-value to the function 'BigFunc', and so is compiled as partially-interruptible which means FuncEval isn't necessarily possible at all points in the method.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Funcevalfailswhilestoppedinnonoptimizedm_EDF2/image_6.png" mce_href="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Funcevalfailswhilestoppedinnonoptimizedm_EDF2/image_6.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=600 alt=image src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Funcevalfailswhilestoppedinnonoptimizedm_EDF2/image_thumb_2.png" width=848 border=0 mce_src="http://blogs.msdn.com/blogfiles/rmbyers/WindowsLiveWriter/Funcevalfailswhilestoppedinnonoptimizedm_EDF2/image_thumb_2.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;In the above case, we can verify that the method Main is not fully-interruptible by using the GCInfo command in SOS:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;.load sos &lt;BR&gt;extension C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded&lt;/P&gt;
&lt;P&gt;!GCInfo 003A00A4 &lt;BR&gt;entry point 003a0070 &lt;BR&gt;Normal JIT generated code &lt;BR&gt;GC info 11e8a09800121a98 &lt;BR&gt;Method info block: &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; method&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; = 0167 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; prolog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; = 32 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&amp;nbsp;&amp;nbsp; =&amp;nbsp; 8 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count&amp;nbsp;&amp;nbsp; =&amp;nbsp; 1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; callee-saved regs&amp;nbsp; = EDI ESI EBX EBP &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp frame&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;STRONG&gt;fully interruptible= no&amp;nbsp; &lt;BR&gt;&lt;/STRONG&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double align&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = no&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; arguments size&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;nbsp; 0 DWORDs &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; stack frame size&amp;nbsp;&amp;nbsp; = 44 DWORDs &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; untracked count&amp;nbsp;&amp;nbsp;&amp;nbsp; =&amp;nbsp; 1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var ptr tab count&amp;nbsp; =&amp;nbsp; 1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; security check obj = yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; exception handlers = yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; edit &amp;amp; continue&amp;nbsp;&amp;nbsp;&amp;nbsp; = yes &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; epilog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at&amp;nbsp;&amp;nbsp; 015F &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; argTabOffset = 5&amp;nbsp; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;H6&gt;&lt;/H6&gt;
&lt;P&gt;First we load sos in the immediate window, then get an address in the method of interest (eg. by looking at the value of the EIP register while we're stopped there) and pass it to the !GCInfo command.&amp;nbsp; The "fully intteruptible=no" line is unusual for debuggable code (one way you can tell it's indeed debuggable is the "edit &amp;amp; continue = yes" which isn't normally the case in optimized code).&lt;/P&gt;
&lt;P&gt;The other, more common, case where this happens is when calling a method with at least 64 arguments (each of 4 bytes).&amp;nbsp; Having a method that takes 64 arguments seems poor style to me (hard to read), but I've seen such code from code-generation tools.&amp;nbsp; Either way, passing 256 bytes by-value on the stack is generally a bad idea from a performance perspective anyway (it's a fair amount of copying of data).&amp;nbsp; It's usually better to group the data into a class and pass that, and/or pass large value-types by reference (eg. with the 'ref' keyword in C#).&lt;/P&gt;
&lt;P&gt;We're looking into relaxing this restriction in a future version of the CLR, but in the meantime if you run into problems with this, I suggest you refactor your code to avoid having methods that take 256 bytes or more in arguments.&amp;nbsp; Perhaps somebody should write an FxCop rule for this.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8872792" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/ICorDebug/default.aspx">ICorDebug</category></item><item><title>Invoking a virtual method non-virtually</title><link>http://blogs.msdn.com/rmbyers/archive/2008/08/16/invoking-a-virtual-method-non-virtually.aspx</link><pubDate>Sun, 17 Aug 2008 02:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8872728</guid><dc:creator>rmbyers</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/8872728.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=8872728</wfw:commentRss><description>&lt;P&gt;Method calls using the C# ‘&lt;A href="http://msdn.microsoft.com/en-us/library/hfw7t1ce.aspx" mce_href="http://msdn.microsoft.com/en-us/library/hfw7t1ce.aspx"&gt;base&lt;/A&gt;’ keyword get compiled to an IL ‘&lt;A href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.call.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.call.aspx"&gt;call&lt;/A&gt;’ instruction, rather than the ‘&lt;A href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.callvirt.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.callvirt.aspx"&gt;callvirt&lt;/A&gt;’ &lt;A href="http://blogs.msdn.com/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx" mce_href="http://blogs.msdn.com/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx"&gt;that is normally used&lt;/A&gt;. This is the one case in C# where a virtual method can be invoked without virtual dispatch. The CLR allows it to be used generally for non-virtual calls, but it’s unverifiable in other cases (see section 3.19 of the &lt;A href="http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20III.pdf" mce_href="http://download.microsoft.com/download/7/3/3/733AD403-90B2-4064-A81E-01035A7FE13C/MS%20Partition%20III.pdf"&gt;CLI specification partition III&lt;/A&gt; for the full definition). &lt;/P&gt;
&lt;P&gt;One place this causes some pain is with &lt;A href="http://blogs.msdn.com/jmstall/archive/category/11475.aspx" mce_href="http://blogs.msdn.com/jmstall/archive/category/11475.aspx"&gt;func-eval&lt;/A&gt;. Func-Eval always does a virtual dispatch on virtual methods, which is why the ‘base’ keyword doesn’t work properly in the watch/immediate window in VS 2008. Mike Stall has a blog entry on this topic here: &lt;A href="http://blogs.msdn.com/jmstall/archive/2006/06/29/funceval-does-virtual-dispatch.aspx" mce_href="http://blogs.msdn.com/jmstall/archive/2006/06/29/funceval-does-virtual-dispatch.aspx"&gt;http://blogs.msdn.com/jmstall/archive/2006/06/29/funceval-does-virtual-dispatch.aspx&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;What Mike doesn’t mention is there is actually a work-around for this. First we need some mechanism to invoke a virtual method non-virtually, and the only one I could find was using Reflection.Emit / lightweight-codegen to emit a ‘call’ instruction. For example, the following method can be used to invoke any virtual method non-virtually:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Call a virtual method non-virtually - like Reflection's MethodInfo.Invoke, 
&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;but doesn't do virtual dispatch.
&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="method"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;The method to invoke&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;The arguments to pass (including 'this')&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;The return value from the call&lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;&amp;lt;/returns&amp;gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;static object &lt;/SPAN&gt;InvokeNonVirtual(&lt;SPAN style="COLOR: #2b91af"&gt;MethodInfo &lt;/SPAN&gt;method, &lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;[] args)
{
    &lt;SPAN style="COLOR: green"&gt;// Reflection doesn't seem to have a way directly (eg. custom binders are 
    // only used for ambiguities).  Using a delegate also always seems to do 
    // virtual dispatch.

    // Use LCG to generate a temporary method that uses a 'call' instruction to
    // invoke the supplied method non-virtually.
    // Doing a non-virtual call on a virtual method outside the class that 
    // defines it will normally generate a VerificationException (PEVerify 
    // says "The 'this' parameter to the call must be the callng method's 
    // 'this' parameter.").  By associating the method with a type ("Program") 
    // in a full-trust assembly, we tell the JIT to skip this verification step.
    // Alternately we might want to associate it with method.DeclaringType - the
    // verification might then pass even if it's not skipped (eg. partial trust).
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;paramTypes = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;Type&lt;/SPAN&gt;&amp;gt;();
    &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(!method.IsStatic)
        paramTypes.Add(method.DeclaringType);
    paramTypes.AddRange(method.GetParameters().Select(p =&amp;gt; p.ParameterType));
    &lt;SPAN style="COLOR: #2b91af"&gt;DynamicMethod &lt;/SPAN&gt;dm = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DynamicMethod&lt;/SPAN&gt;(
        &lt;SPAN style="COLOR: #a31515"&gt;"NonVirtualInvoker"&lt;/SPAN&gt;,    &lt;SPAN style="COLOR: green"&gt;// name
        &lt;/SPAN&gt;method.ReturnType,      &lt;SPAN style="COLOR: green"&gt;// same return type as method we're calling 
        &lt;/SPAN&gt;paramTypes.ToArray(),   &lt;SPAN style="COLOR: green"&gt;// same parameter types as method we're calling
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Program&lt;/SPAN&gt;));       &lt;SPAN style="COLOR: green"&gt;// associates with this full-trust code
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;ILGenerator &lt;/SPAN&gt;il = dm.GetILGenerator();
    &lt;SPAN style="COLOR: blue"&gt;for &lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;int &lt;/SPAN&gt;i = 0; i &amp;lt; paramTypes.Count; i++)
        il.Emit(&lt;SPAN style="COLOR: #2b91af"&gt;OpCodes&lt;/SPAN&gt;.Ldarg, i);             &lt;SPAN style="COLOR: green"&gt;// load all args
    &lt;/SPAN&gt;il.EmitCall(&lt;SPAN style="COLOR: #2b91af"&gt;OpCodes&lt;/SPAN&gt;.Call, method, &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;);   &lt;SPAN style="COLOR: green"&gt;// call the method non-virtually
    &lt;/SPAN&gt;il.Emit(&lt;SPAN style="COLOR: #2b91af"&gt;OpCodes&lt;/SPAN&gt;.Ret);                      &lt;SPAN style="COLOR: green"&gt;// return what the call returned

    // Call the emitted method, which in turn will call the method requested
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;return &lt;/SPAN&gt;dm.Invoke(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;, args);
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;With a method like the above available, we can use statements like the following (in the program or in the immediate window) to invoke a method non-virtually (i.e. to simulate the ‘base’ keyword):&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: green"&gt;// Foo is some class that overrides ToString
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Foo &lt;/SPAN&gt;f = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Foo&lt;/SPAN&gt;();
&lt;SPAN style="COLOR: #2b91af"&gt;MethodInfo &lt;/SPAN&gt;m = &lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;).GetMethod(&lt;SPAN style="COLOR: #a31515"&gt;"ToString"&lt;/SPAN&gt;, 
    &lt;SPAN style="COLOR: #2b91af"&gt;BindingFlags&lt;/SPAN&gt;.Instance | &lt;SPAN style="COLOR: #2b91af"&gt;BindingFlags&lt;/SPAN&gt;.Public);

&lt;SPAN style="COLOR: green"&gt;// s1 will be the same as f.ToString - whatever Foo.ToString returns
&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;string &lt;/SPAN&gt;s1 = (&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;)m.Invoke(f, 
    &lt;SPAN style="COLOR: #2b91af"&gt;BindingFlags&lt;/SPAN&gt;.Instance | &lt;SPAN style="COLOR: #2b91af"&gt;BindingFlags&lt;/SPAN&gt;.InvokeMethod, &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;);

&lt;SPAN style="COLOR: green"&gt;// s2 will be the return value from Object.ToString
&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;string &lt;/SPAN&gt;s2 = (&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;)InvokeNonVirtual(m, &lt;SPAN style="COLOR: blue"&gt;new object&lt;/SPAN&gt;[] {f});&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;We can also avoid having to get the ‘InvokeNonVirtual’ method into the target program at all by entering code like the following into the immediate window (depending on what method you want to invoke, eg. this invokes 'ToString' non-virtually on object 'o').:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: #2b91af"&gt;MethodInfo &lt;/SPAN&gt;m1 = &lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;).GetMethod(&lt;SPAN style="COLOR: #a31515"&gt;"ToString"&lt;/SPAN&gt;, 
    &lt;SPAN style="COLOR: #2b91af"&gt;BindingFlags&lt;/SPAN&gt;.Instance | &lt;SPAN style="COLOR: #2b91af"&gt;BindingFlags&lt;/SPAN&gt;.Public);
&lt;SPAN style="COLOR: #2b91af"&gt;DynamicMethod &lt;/SPAN&gt;dm = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;DynamicMethod&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"ToStringInvoker"&lt;/SPAN&gt;, 
    &lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;), &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Type&lt;/SPAN&gt;[] { &lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;) }, &lt;SPAN style="COLOR: blue"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;Program&lt;/SPAN&gt;));
&lt;SPAN style="COLOR: #2b91af"&gt;ILGenerator &lt;/SPAN&gt;il = dm.GetILGenerator();
il.Emit(&lt;SPAN style="COLOR: #2b91af"&gt;OpCodes&lt;/SPAN&gt;.Ldarg_0);
il.EmitCall(&lt;SPAN style="COLOR: #2b91af"&gt;OpCodes&lt;/SPAN&gt;.Call, m1, &lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;);
il.Emit(&lt;SPAN style="COLOR: #2b91af"&gt;OpCodes&lt;/SPAN&gt;.Ret);
&lt;SPAN style="COLOR: blue"&gt;string &lt;/SPAN&gt;s3 = (&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;)dm.Invoke(&lt;SPAN style="COLOR: blue"&gt;null&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;new object&lt;/SPAN&gt;[] { o });&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Yes, I realize typing this into the immediate window whenever you want to say ‘base’ is kind of a pain (perhaps completely impractical). But the interesting thing here is that it means a debugger could build support for the ‘base’ keyword without any additional work from ICorDebug or the CLR! Of course, I still agree with Mike that it’s a reasonable feature-request to have func-eval support an option for non-virtual dispatch. I just don’t see it making its way to the top of our wish-list anytime soon (unless we get strong customer feedback of course).&lt;/P&gt;
&lt;P&gt;This also raises an interesting question about the design of func-eval. Should we have just supported calling a few key reflection APIs and made all evals go through reflection? This certainly would have been simpler and more reliable for the CLR – otherwise we have to duplicate a lot of the logic about how to marshal values and call methods that Reflection already needs to have. Then again, there’s always going to be the challenge of marshalling between ICorDebugValue instances and objects in the target, and that’s a pretty big chunk of what’s required to make func-eval work.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8872728" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/ICorDebug/default.aspx">ICorDebug</category></item><item><title>Customizing PDB lookup for source information in StackTrace</title><link>http://blogs.msdn.com/rmbyers/archive/2007/06/21/customizing-pdb-lookup-for-source-information-in-stacktrace.aspx</link><pubDate>Fri, 22 Jun 2007 08:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3453411</guid><dc:creator>rmbyers</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/3453411.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=3453411</wfw:commentRss><description>&lt;P&gt;The &lt;A href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx"&gt;System.Diagnostics.StackTrace class&lt;/A&gt; in .NET can be used to generate a textual representation of the current callstack.&amp;nbsp; This is used, for example, by &lt;A href="http://msdn2.microsoft.com/en-us/library/system.exception.tostring.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.exception.tostring.aspx"&gt;Exception.ToString()&lt;/A&gt;. If requested by the caller, StackTrace can include source file locations (file names and line numbers, etc.) for each frame whose module has a &lt;A href="http://msdn2.microsoft.com/en-us/library/ms241903.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms241903.aspx"&gt;PDB file&lt;/A&gt; available to the CLR.&amp;nbsp; PDB files are designed to be used primarily in development-time scenarios, and so the idea here is that when you're developing or testing your application and it spits out an exception (eg. to a log file, or an unhandled exception to the console), it will help you to debug the issue if you can see exactly where in the leaf method the exception was thrown, and where exactly each child function was called (actually it's not technically "exactly" - if &lt;A href="http://msdn2.microsoft.com/en-us/library/t0hfscdc(vs.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/t0hfscdc(vs.71).aspx"&gt;JIT optimizations&lt;/A&gt; are enabled the results may be approximate, and frames may be missing completely due to inlining).&amp;nbsp; If you've done much .NET programming, you probably knew all this already.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;The more interesting (and less well documented) question I want to address is where exactly you must place your PDB files for this to work.&amp;nbsp; The CLR will look next to the corresponding module (DLL or EXE), and also check a few other standard locations (those local paths specified by the _NT_SYMBOL_PATH environment variable for example, and I believe the Windows system directory).&amp;nbsp; In fact, it's not really the CLR controlling any of this, but the &lt;A href="http://msdn2.microsoft.com/en-us/library/ms230866.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms230866.aspx"&gt;ISymUnmanagedBinder::GetReaderForFile&lt;/A&gt; API from diasymreader.dll, which itself is implemented on top of the &lt;A href="http://msdn2.microsoft.com/en-us/library/12kk9t39(VS.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/12kk9t39(VS.71).aspx"&gt;IDiaDataSource::loadDataForExe&lt;/A&gt;&amp;nbsp;API.&amp;nbsp; Since this support for source locations is designed for development time, when you're generally running binaries you've just built - the PDBs are almost always next to the binaries and this works great.&lt;/P&gt;
&lt;P&gt;Occasionally we get requests from people who like this feature but complain that the CLR isn't flexible enough to find their PDB files where they want to put them.&amp;nbsp; Sometimes this stems from wanting to use this feature for something it wasn't designed, such as shipping PDBs with your product and logging/reporting errors from the field.&amp;nbsp; For that scenario you're usually MUCH better off using &lt;A href="http://winqual.microsoft.com/" mce_href="http://winqual.microsoft.com/"&gt;Windows Error Reporting&lt;/A&gt;&amp;nbsp;and minidumps.&amp;nbsp; You generally do not want to ship your PDBs to your customers (they're big, and can make it easier to reverse engineer your code - although this is a much bigger concern for unmanaged C++ code than .NET code).&amp;nbsp; In other cases, you may want to generate machine-readable stack traces (with module names, method tokens and IL offsets), and then post-process them using PDB files at your location to get source location information.&lt;/P&gt;
&lt;P&gt;But, there are a few scenarios where it does really make sense to want more flexibility in how PDBs are located for the StackTraces generated at runtime.&amp;nbsp; For example, I recently got a request through product support from a customer with a large test environment where they were deploying their actual product.&amp;nbsp; They keep all their PDBs (1TB+ of them!) on a &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx" mce_href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx"&gt;symbol server&lt;/A&gt;, and they would like to be able to use them to generate stack traces with source info without having to deploy PDBs to all their test machines (in the proper directories).&amp;nbsp; Although the CLR doesn't support this directly, there isn't any reason you can't implement this yourself.&amp;nbsp; The CLR StackTrace class exposes StackFrame objects which have all the information you need to map back to source addresses given an ISymbolReader instance.&amp;nbsp; ISymbolReader instances can be created directly (controlling PDB location policy manaually with ISymbolUnmanagedBinder2::GetReaderForFile2) by calling into diasymreader.dll through COM interop.&amp;nbsp; I've posted sample code for a StackTraceSymbolProvider class that does this &lt;A href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx" mce_href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx"&gt;here&lt;/A&gt; (using &lt;A href="http://www.microsoft.com/downloads/details.aspx?familyid=38449a42-6b7a-4e28-80ce-c55645ab1310&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?familyid=38449a42-6b7a-4e28-80ce-c55645ab1310&amp;amp;displaylang=en"&gt;MDbg's&lt;/A&gt; COM interop wrappers for diasymreader.dll).&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Here's an example of how this code can be used to print out a StackTrace from an Exception while explicitly controlling the directories searched (searchPath is a semi-colon separated list of directories including &lt;A href="http://support.microsoft.com/kb/311503" mce_href="http://support.microsoft.com/kb/311503"&gt;SRV* entries&lt;/A&gt; for symbol servers), and whether things like a symbol server will be checked:&lt;/P&gt;&lt;PRE class=code&gt;            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;catch&lt;/SPAN&gt; (System.&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Exception&lt;/SPAN&gt; e)
            {
                st = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;StackTrace&lt;/SPAN&gt;(e, &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;true&lt;/SPAN&gt;);
                &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;StackTraceSymbolProvider&lt;/SPAN&gt; stsp = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;StackTraceSymbolProvider&lt;/SPAN&gt;(searchPath,
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowSymbolServerAccess |
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowOriginalPathAccess |
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowReferencePathAccess |
                    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;SymSearchPolicies&lt;/SPAN&gt;.AllowRegistryAccess);

                &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Console&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: rgb(163,21,21)"&gt;"Custom stack trace:"&lt;/SPAN&gt;);
                &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Console&lt;/SPAN&gt;.WriteLine(stsp.StackTraceToStringWithSourceInfo(st));
            }
&lt;/PRE&gt;
&lt;P&gt;To get this flexibility you have to re-implement some of the formatting done by StackTrace.ToString(), but you might want the flexibility to control this anyway (for example, it's easy to include column numbers in addition to line numbers).&amp;nbsp; It's non-trivial to wire this all up (especially if you're not familiar with &lt;A href="http://msdn2.microsoft.com/en-us/library/sd10k43k(VS.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/sd10k43k(VS.71).aspx"&gt;COM-interop&lt;/A&gt;), but it's all plumbing really.&amp;nbsp; Hopefully &lt;A href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx" mce_href="http://blogs.msdn.com/rmbyers/pages/code-sample-stacktrace-with-manual-symbol-lookup.aspx"&gt;this sample code&lt;/A&gt; will save some of you the hassle of figuring out this plumbing yourself.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3453411" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/PDBs/default.aspx">PDBs</category></item><item><title>More on generic variance</title><link>http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx</link><pubDate>Fri, 02 Jun 2006 04:44:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:613690</guid><dc:creator>rmbyers</dc:creator><slash:comments>20</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/613690.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=613690</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;In &lt;A href="/rmbyers/archive/2005/02/16/375079.aspx"&gt;my entry on generic variance in the CLR&lt;/A&gt;, I said that you can’t convert a List&amp;lt;String&amp;gt; to a List&amp;lt;Object&amp;gt;, or even an IEnumerable&amp;lt;String&amp;gt; to IEnumerable&amp;lt;Object&amp;gt;.&amp;nbsp; I should point out however that the real-world scenarios where you’d want to do this usually involve passing an object of a more specific type to an API that (for abstraction reasons) takes a less specific type.&amp;nbsp; For example, say you have a class hierarchy like this:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;abstract&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Shape&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;abstract&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; ComputeArea();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Square&lt;/SPAN&gt; : &lt;SPAN style="COLOR: teal"&gt;Shape&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; Square(&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; height)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; m_height = height;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; ComputeArea()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; m_height * m_height;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; m_height;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Circle&lt;/SPAN&gt; : &lt;SPAN style="COLOR: teal"&gt;Shape&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; Circle(&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; radius)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; m_radius = radius;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; ComputeArea()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Math&lt;/SPAN&gt;.PI * m_radius * m_radius;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; m_radius;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;You’d like to be able to use it uniformly like this:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Program&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;void&lt;/SPAN&gt; &lt;?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /&gt;&lt;st1:place w:st="on"&gt;Main&lt;/st1:place&gt;(&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;[] args)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: teal"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: teal"&gt;Square&lt;/SPAN&gt;&amp;gt; ls = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: teal"&gt;Square&lt;/SPAN&gt;&amp;gt;(); &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ls.Add(&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Square&lt;/SPAN&gt;(2));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ls.Add(&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Square&lt;/SPAN&gt;(3));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; totS = GetTotalArea(ls); &lt;FONT color=#008000&gt;// won’t compile&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: teal"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: teal"&gt;Circle&lt;/SPAN&gt;&amp;gt; lc = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: teal"&gt;Circle&lt;/SPAN&gt;&amp;gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lc.Add(&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Circle&lt;/SPAN&gt;(2));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lc.Add(&lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;Circle&lt;/SPAN&gt;(3));&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; totC = GetTotalArea(lc); &lt;FONT color=#008000&gt;// won’t compile&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; GetTotalArea( &lt;SPAN style="COLOR: teal"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: teal"&gt;Shape&lt;/SPAN&gt;&amp;gt; l) &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; total = 0;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;foreach&lt;/SPAN&gt; (&lt;SPAN style="COLOR: teal"&gt;Shape&lt;/SPAN&gt; s &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; l)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; total += s.ComputeArea();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; total;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This would only work if C# supported generic variance and IEnumerable was defined as IEnumerable&amp;lt;+T&amp;gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, there is another option in this case.&amp;nbsp; You could make GetTotalArea a generic method and rely on a base-type constraint:&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; GetTotalArea&amp;lt;T&amp;gt;(&lt;SPAN style="COLOR: teal"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;T&amp;gt; l)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;where&lt;/SPAN&gt; T : &lt;SPAN style="COLOR: teal"&gt;Shape&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;double&lt;/SPAN&gt; total = 0;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;foreach&lt;/SPAN&gt; (&lt;SPAN style="COLOR: teal"&gt;Shape&lt;/SPAN&gt; s &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; l)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;total += s.ComputeArea();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; total;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Now the above Main method will work perfectly, you don’t even have to modify it to specify the type parameters (C#’s type inference can figure them out automatically).&amp;nbsp; So although you're not really converting an IEnumerable&amp;lt;Square&amp;gt; to an IEnumerable&amp;lt;Shape&amp;gt;, you&amp;nbsp;are able to use it that way.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This is certainly great.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;And in practice, most .NET developers will find the support in .NET 2.0 for generics to be more than powerful enough.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, if you’re trying to do some serious “generic programming” &lt;A href="http://faculty.cs.tamu.edu/jarvi/papers/cmp_gp.pdf"&gt;[3]&lt;/A&gt;, or if you’re excited by programming language theory like I am, then this does still leave something to be desired.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Most notably, we can specify an upper-bound using a constraint like this (rather than require our language to support covariant type parameters), but the CLR and C# don’t have support for lower bounds (“supertype constraints”) so you can’t use this technique in place of contravariant type parameters (eg. my IComparer&amp;lt;-T&amp;gt; example).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;See section 4.4 (“Comparison with Parametric Methods”) of &lt;A href="http://citeseer.ist.psu.edu/igarashi02variancebased.html"&gt;[1]&lt;/A&gt; for more details.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Java 5 addresses these scenarios with “Wildcard types” &lt;A href="http://www.daimi.au.dk/~madst/tool/tool2004/papers/wildcards.pdf"&gt;[2]&lt;/A&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Eg. you would use a “List&amp;lt;? extends Shape&amp;gt;” in Java to implement my example above, and there is also a syntax “? super T” for lower-bounds.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It’s&amp;nbsp;interesting to note that the authors of the paper on wildcards indicate that the main advantage of wildcard types over using normal generic methods (as I’ve done above) is that wildcard types don’t require exact type information (see section 4.4 of &lt;A href="http://www.daimi.au.dk/~madst/tool/tool2004/papers/wildcards.pdf"&gt;[2]&lt;/A&gt;).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The big difference between generics in .NET and Java is that in .NET, the CLR supports generics to the core and so we have exact type information everywhere (which is why you can get information about generic types using Reflection at run-time).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In Java, generics are “erased” by the compiler, and so at run-time, the information about generic instantiations are lost.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Using erasure has the benefit of better compatibility with old code and a much simpler implementation, but extending the VM (like we did for the CLR) has several important benefits including avoiding boxing for instantiations at value types and therefore better performance (eg. a List&amp;lt;int&amp;gt; can be very efficient), and the ability to use exact type information at run-time.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The big difference between wildcards and generic variance in the CLR is that wildcard types are an example of “usage-site variance” where MSIL&amp;nbsp;uses “definition-site variance” (meaning it’s the type definition that specifies the variance annotation, not the user of the type).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I was reading about a cool academic programming language called &lt;A href="http://scala.epfl.ch/index.html"&gt;Scala&lt;/A&gt; recently, and was pleased to see that after some experience with usage-site variance, they decided to switch to definition-site variance because they found it easier to use correctly (see “Comparison with wildcards” in &lt;A href="http://scala.epfl.ch/docu/files/ScalaOverview.pdf"&gt;[4]&lt;/A&gt;).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Scala is a very cool language (my programming languages professor recently mentioned it as a great example of a language on the forefront of modern academic language design), and&amp;nbsp;can target .NET.&amp;nbsp; Unfortunately they haven’t built support for the V2.0 CLR yet so they aren’t actually making use of the definition-site variance support in the CLR (for the moment &amp;lt;grin&amp;gt;).&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Anyway, I think that’s about all I have to say about generic variance.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;I’ve got a &lt;A href="http://www.cs.washington.edu/education/courses/csep505/06sp/"&gt;programming languages&lt;/A&gt; exam on Tuesday (I’m working on my masters in computer science) so I think I better stop procrastinating and study for it &amp;lt;grin&amp;gt;.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;References&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;[1] &lt;A href="http://pag.csail.mit.edu/reading-group/variance-ECOOP02.pdf"&gt;On variance-based subtyping for parametric types&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;[2] &lt;A href="http://www.daimi.au.dk/~madst/tool/tool2004/papers/wildcards.pdf"&gt;Adding Wildcards to the Java Programming Language&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;[3] &lt;A href="http://faculty.cs.tamu.edu/jarvi/papers/cmp_gp.pdf"&gt;A Comparative Study of Language Support for Generic Programming&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;[4] &lt;A href="http://scala.epfl.ch/docu/files/ScalaOverview.pdf"&gt;An Overview of the Scala Programming Language (2. Edition)&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=613690" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/Languages/default.aspx">Languages</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category></item><item><title>DebuggingModes.IgnoreSymbolStoreSequencePoints</title><link>http://blogs.msdn.com/rmbyers/archive/2005/09/08/debuggingmodes-ignoresymbolstoresequencepoints.aspx</link><pubDate>Fri, 09 Sep 2005 03:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:462676</guid><dc:creator>rmbyers</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/462676.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=462676</wfw:commentRss><description>&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/rmbyers/archive/2005/06/26/432922.aspx" mce_href="http://blogs.msdn.com/rmbyers/archive/2005/06/26/432922.aspx"&gt;last post&lt;/A&gt;&amp;nbsp;I gave an overview of the DebuggableAttribute, what values the C# compiler gives it, and how the CLR uses those values.&amp;nbsp; I mentioned that with /debug+, the C# compiler sets the IgnoreSymbolStoreSequencePoints DebuggingModes bit, but I didn't describe what this bit does.&amp;nbsp; Understanding sequence points and ths IgnoreSymbolStoreSequencePoints bit is important for anyone writing a compiler for .NET (including one that uses Reflection.Emit).&lt;/P&gt;
&lt;P&gt;A sequence point is used to mark a spot in the IL code that corresponds to a specific location in the original source.&amp;nbsp; For Reflection.Emit, they are emitted by the ILGenerator.MarkSequencePoint method.&amp;nbsp; This serves two purposes.&amp;nbsp; First to allow debuggers (and the StackTrace class) to map IL offsets back to source and line information.&amp;nbsp; Secondly to tell the JIT compiler that it must preserve this location uniquely in the generated native code so that a user could, for example, set a breakpoint on it (see Mike's &lt;A href="http://blogs.msdn.com/jmstall/archive/2004/10/03/237137.aspx" mce_href="http://blogs.msdn.com/jmstall/archive/2004/10/03/237137.aspx"&gt;blog entry&lt;/A&gt; for more details).&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Since they're only needed for debugging scenarios, the location of sequence points, and their mapping back to source locations, are stored in the PDB file.&amp;nbsp; Unfortunately this means that the JIT compiler has to open the PDB file and read this data any time it compiles a method with optimizations disabled (if JIT optimizations are enabled, then it doesn't care about sequence points in order to get the best codegen possible).&amp;nbsp; The PDB file format is quite complicated, and has a long legacy.&amp;nbsp; So as you might imagine, there is an unfortunate&amp;nbsp;performance penalty here.&lt;/P&gt;
&lt;P&gt;Now in addition to the sequence points specified in the PDB file ("explicit sequence points"), the JIT also infers additional sequence points based on the IL code ("implicit sequence points").&amp;nbsp; For example, it adds an implicit sequence at every point where the IL evaluation stack is empty, or on any&amp;nbsp;"nop" instruction.&amp;nbsp; So in Whidbey we added the IgnoreSymbolStoreSequencePoints bit to allow compilers to indicate to the JIT that they are content with the JITs rules for implicit sequence points, and there is no need for the JIT to look in the PDB file for more.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;So our official recommendation is that all compilers (including those using Reflection.Emit) set the IgnoreSymbolStoreSequencePoints bit and rely on "nop" instructions to ensure the JIT places sequence points at the right place.&amp;nbsp; This can make a nice JIT performance improvement,&amp;nbsp;and also has some other benefits related to not needing to read the PDB file at JIT time (eg. it may not be available).&amp;nbsp; The Whidbey C# and VB compilers do this, but unfortunately the managed C++ compiler does not.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=462676" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/PDBs/default.aspx">PDBs</category></item><item><title>DebuggableAttribute and dynamic assemblies</title><link>http://blogs.msdn.com/rmbyers/archive/2005/06/26/432922.aspx</link><pubDate>Mon, 27 Jun 2005 07:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:432922</guid><dc:creator>rmbyers</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/432922.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=432922</wfw:commentRss><description>&lt;P&gt;Mike Stall has &lt;a href="http://blogs.msdn.com/jmstall/archive/2005/02/03/366429.aspx"&gt;a great little sample&lt;/A&gt; showing how to make your dynamically generated code debuggable.&amp;nbsp; However, there is one more detail you should be aware of.&amp;nbsp; By default the JIT compiler will enable optimizations for the module, making debugging difficult or (in the case of JMC-mode in VS) impossible.&amp;nbsp; If you run your program from within Visual Studio and have the “Suppress JIT optimizations on module load” option enabled, then it’ll work fine. However, I believe this setting in VS is now (as of the June CTP) disabled by default in order to minimize any changes to your program’s behaviour when run under the debugger.&amp;nbsp; Additionally, optimizations would also be enabled it you attached to an already running process.&lt;/P&gt;
&lt;P&gt;Compilers like csc.exe have command line options such as /debug and /optimize that affect how the JIT generates code for the assembly.&amp;nbsp; The compiler communicates this information to the CLR by attaching a System.Diagnostics.DebuggableAttribute to the assembly.&amp;nbsp; This attribute contains a DebuggingModes value which is a bit-mask of various flags.&amp;nbsp; Here are the flags that the Whidbey C# compiler emits for the various combinations of compiler options:&lt;/P&gt;
&lt;P&gt;
&lt;TABLE cellSpacing=1 cellPadding=1&gt;
&lt;TR&gt;
&lt;TD&gt;/debug-&lt;/TD&gt;
&lt;TD&gt;Retail build: No attribute emitted (same as specifying DebuggingModes.None).&amp;nbsp; &lt;BR&gt;Setting /o+ or /o- doesn’t change anything when debug mode is disabled.&amp;nbsp; &lt;BR&gt;/debug- is the default and so can be omitted.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;/debug+&lt;/TD&gt;
&lt;TD&gt;Debug build: Default, IgnoreSybmolStoreSequencePoints, EnableEditAndContinue DisableOptimizations.&amp;nbsp; &lt;BR&gt;/o- is the default here.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;/debug+ /o+&lt;/TD&gt;
&lt;TD&gt;Debug optimized: Default, IgnoreSybmolStoreSequencePoints.&amp;nbsp; &lt;BR&gt;In Whidbey this is essentially the same thing as /debug-.&lt;/TD&gt;&lt;/TR&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;Note that before Whidbey, the “Default” flag was used to “enable JIT tracking”.&amp;nbsp; JIT tracking meant we would track information necessary for debugging such as IL/native maps (for converting native address offsets to IL offsets and vice versa).&amp;nbsp; In Whidbey we have an efficient form of JIT tracking enabled all of the time, so this flag is now basically meaningless.&amp;nbsp; However, we need to ensure the Whidbey CLR runs Everett binaries in the same way, so for backwards compatibility we still require the Default flag to be present if we’re going to do things like disable JIT optimizations.&lt;/P&gt;
&lt;P&gt;So, if you want to emit a dynamic assembly which is always debuggable (similar to using the C# compiler’s /debug+ option), then you need to use the following code after calling DefineDynamicAssembly:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;// Add a debuggable attribute to the assembly saying to disable optimizations&lt;BR&gt;Type daType = typeof(DebuggableAttribute);&lt;BR&gt;ConstructorInfo daCtor = daType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });&lt;BR&gt;CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DebuggableAttribute.DebuggingModes.DisableOptimizations | &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DebuggableAttribute.DebuggingModes.Default });&lt;BR&gt;assemblyBuilder.SetCustomAttribute(daBuilder);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Note that it’s best to do this before calling DefineDynamicModule.&amp;nbsp; Visual Studio, for example, looks at the optimization setting by calling ICorDebugModule2.GetJITCompilerFlags as soon as it gets a LoadModule event (which is triggered by DefineDynamicModule).&amp;nbsp; If you haven’t emitted the DebuggableAttribute yet, VS will think optimizations are enabled and will prevent debugging of the module if JMC is enabled.&lt;/P&gt;
&lt;P&gt;It’s amazing how complicated the concept of “debug build” can be here, especially when you add in backwards compatibility, debugger overrides, various config file overrides, etc.&amp;nbsp; Thankfully, the story is simpler in Whidbey since we no longer have to worry about JIT tracking.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=432922" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category></item><item><title>Run-time exception checking</title><link>http://blogs.msdn.com/rmbyers/archive/2005/04/30/413752.aspx</link><pubDate>Sat, 30 Apr 2005 23:32:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:413752</guid><dc:creator>rmbyers</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/413752.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=413752</wfw:commentRss><description>&lt;P&gt;One of our partners asked us how a .NET program can tell what the currently active “try” blocks are on the stack.&amp;nbsp; This seemed like a dubious thing to want to do, but regardless a colleague of mine whipped up some sample code that uses the StackTrace class and reflection to do this.&amp;nbsp; We were talking about the possible uses of this, and most of them seemed pretty evil.&amp;nbsp; Changing program behaviour based on dynamic program inspection can lead to programs that are hard to reason about and brittle due to violating abstraction boundaries and implicit coupling.&amp;nbsp; Not to mention the fact that in optimized builds, some data may be missing from the StackTrace due to in-lining or other optimizations.&lt;/P&gt;
&lt;P&gt;However, in-process inspection mechanisms like the StackTrace class can be incredibly useful for diagnostics purposes.&amp;nbsp; Perhaps in certain situations, it would be valuable to be able to write assertions like “If I throw a FooException, it should be handled by somebody”. As you probably know, there is a lot of debate about the value of checked exceptions, but I’m not going to discuss that here, see the Artima interviews with &lt;A href="http://www.artima.com/intv/handcuffs.html"&gt;Anders Hejlsberg&lt;/A&gt;&amp;nbsp;and &lt;A href="http://www.artima.com/intv/solid.html"&gt;James Gosling&lt;/A&gt; for a start.&amp;nbsp; We all know that validating your assumptions with assertions is a critical part of writing quality software, especially for large systems.&amp;nbsp; So if you’re making some assumptions about exception behaviour, it seems logical to want to check those assumptions at run-time with assertions.&amp;nbsp; Assertions can also be useful for making you aware of changes in behaviour that might have an impact on an area you didn’t anticipate.&amp;nbsp; You could imagine more complex checks like “The only catch handler for System.Exception is the one I know about in the top loop of my application” (nothing is more annoying then having some library code swallow your exceptions).&amp;nbsp; Of course checking these sorts of things statically (with tools like FxCop) is generally preferable to run-time checks, but our managed static analysis tools are still quite primitive, and it is very difficult to do complete static analysis in the presence of dynamic control flow mechanisms like reflection and delegates.&lt;/P&gt;
&lt;P&gt;Anyway, here is some sample code that shows how you could write such assertions (I apologize for the lack of syntax highlighting – this new community server software doesn’t properly paste formatted text).&amp;nbsp; I’m still not convinced this is necessarily a good idea, but it seems to have some intriguing possibilities nonetheless.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;// Get a list of all the try clauses that are active on the stack that would&lt;BR&gt;// catch exceptions of the specified type.&lt;BR&gt;static public List&amp;lt;ExceptionHandlingClause&amp;gt; GetActiveTryClauses(Type exType)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; List&amp;lt;ExceptionHandlingClause&amp;gt; activeTryClauses =&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; new List&amp;lt;ExceptionHandlingClause&amp;gt;();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;nbsp; StackTrace stackTrace = new StackTrace();&lt;BR&gt;&amp;nbsp; StackFrame[] frames = stackTrace.GetFrames();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;&amp;nbsp; // Start at 1 to skip the GetActiveTryClauses frame.&lt;BR&gt;&amp;nbsp; for (int i = 1; i &amp;lt; frames.Length; i++)&lt;BR&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackFrame frame = frames[i];&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MethodBase method = frame.GetMethod();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MethodBody body = method.GetMethodBody();&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Only consider methods that have an IL body.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (body != null)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IList&amp;lt;ExceptionHandlingClause&amp;gt; ehClauses = body.ExceptionHandlingClauses;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (ExceptionHandlingClause ehClause in ehClauses)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (ehClause.Flags == ExceptionHandlingClauseOptions.Clause)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Only consider clauses which are active on the current stack&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int offsetInFrame = frame.GetILOffset();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int tryStartOffset = ehClause.TryOffset;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int tryEndOffset = tryStartOffset + ehClause.TryLength;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ((offsetInFrame &amp;gt;= tryStartOffset) &amp;amp;&amp;amp; (offsetInFrame &amp;lt; tryEndOffset))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // If desired, only collect clauses that would catch the specified type&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (exType == null || ehClause.CatchType.IsAssignableFrom(exType))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; activeTryClauses.Add(ehClause);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp; return activeTryClauses;&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;public static bool IsCaught(System.Type type)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp; List&amp;lt;ExceptionHandlingClause&amp;gt; handlers = GetActiveTryClauses(type);&lt;BR&gt;&amp;nbsp; return (handlers.Count &amp;gt; 0);&lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This allows you to write simple checks like the following:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;// Ensure someone will handle any IO failure here&lt;BR&gt;Debug.Assert(TryClauseInfo.IsCaught(typeof(System.IO.IOException)));&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#000080 size=2&gt;// Ensure no-one is catching all exceptions&lt;BR&gt;Debug.Assert(!TryClauseInfo.IsCaught(typeof(System.Exception)));&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Or you could even write more complex checks based on the ExceptionHandlingClause information.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;What do you think?&amp;nbsp; Are there situations in your applications where you could get value out of using assertions like this? Can you think of any other uses for this code that wouldn't be totally evil?&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=413752" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category></item><item><title>Generic type parameter variance in the CLR</title><link>http://blogs.msdn.com/rmbyers/archive/2005/02/16/generic-type-parameter-variance-in-the-clr.aspx</link><pubDate>Thu, 17 Feb 2005 10:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:375079</guid><dc:creator>rmbyers</dc:creator><slash:comments>19</slash:comments><comments>http://blogs.msdn.com/rmbyers/comments/375079.aspx</comments><wfw:commentRss>http://blogs.msdn.com/rmbyers/commentrss.aspx?PostID=375079</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;When people start using C# generics for the first time, they are sometimes surprised that they can’t convert between related generic instances.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, since you can convert a &lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes"&gt;string&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt; to an &lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes"&gt;object&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;, shouldn’t you also be able to convert a &lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-font-weight: bold"&gt;List&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes"&gt;&amp;lt;string&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="mso-ansi-language: EN-CA"&gt; &lt;SPAN lang=EN&gt;to a &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-font-weight: bold"&gt;List&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes"&gt;&amp;lt;object&amp;gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;After all, you can convert a &lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes"&gt;string[]&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt; to an &lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes"&gt;object[]&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;, why should List&amp;lt;T&amp;gt; be any different?&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;More formally, in C# v2.0 if T is a subtype of U, then T[] is a subtype of U[], but G&amp;lt;T&amp;gt; is not a subtype of G&amp;lt;U&amp;gt; (where G is any generic type).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In type-theory terminology, we describe this &lt;/SPAN&gt;behavior&lt;SPAN style="mso-ansi-language: EN-CA"&gt; &lt;SPAN lang=EN&gt;by saying that C# array types are “covariant” and generic types are “invariant”.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;There is actually a reason why you might consider generic type invariance to be a good thing.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Consider the following code:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; TEXT-INDENT: 0.5in; mso-layout-grid-align: none"&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: navy; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;List&lt;/SPAN&gt;&lt;/B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt; ls = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;B&gt;&lt;SPAN style="COLOR: navy"&gt;List&lt;/SPAN&gt;&lt;/B&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt;();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;ls.Add("test");&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;B&gt;&lt;SPAN style="COLOR: navy"&gt;List&lt;/SPAN&gt;&lt;/B&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;&amp;gt; lo = ls;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Can't do this in C#&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt; o1 = lo[0];&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// ok – converting string to object&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;lo[0] = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;();&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// ERROR – can’t convert object to string&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;If this were allowed, the last line would have to result in a run-time type-check (to preserve type safety), which could throw an exception (eg. InvalidCastException).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This wouldn’t be the end of the world, but it would be unfortunate.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Part of the benefit of generic types is that it helps to avoid the run-time checking and error handling overhead involved in converting back and forth from a base type (object in C#).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It simplifies things greatly (both from a developer and run-time perspective) to be able to say that a variable of type List&amp;lt;object&amp;gt; can for sure hold any object.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;So what about arrays, don’t we have the exact problem there?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Yep.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This was a hotly debated aspect to C#/CLR design.&amp;nbsp; Java also has covariant array types, and whether or not this is a language flaw has been &lt;A href="http://c2.com/cgi/wiki?JavaArraysBreakTypeSafety" mce_href="http://c2.com/cgi/wiki?JavaArraysBreakTypeSafety"&gt;debated&lt;/A&gt; for ages. Jim Miller has an interesting annotation in his &lt;A href="http://www.amazon.com/exec/obidos/tg/detail/-/0321154932" mce_href="http://www.amazon.com/exec/obidos/tg/detail/-/0321154932"&gt;CLI book&lt;/A&gt; (pg&amp;nbsp;59) where he says "The decision to support covariant arrays was primarily to allow Java to run on the VES.&amp;nbsp; The&amp;nbsp;covariant design is not thought to be the best design in&amp;nbsp;general, but it was chosen in the interest of broad reach".&amp;nbsp;&amp;nbsp;[Update: I've heard that Bill Joy, one of the original Java designers, has since said that he tried to remove array covariance in 1995 but wasn't able to do it in time, and has regretted having it in Java ever since]&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;Let’s get back to our original question.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;What if you really did want covariant generic types in a .NET language?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Does the CLR really prevent that?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Well, you may recall that I &lt;A href="http://blogs.msdn.com/rmbyers/archive/2005/02/08/369646.aspx" mce_href="http://blogs.msdn.com/rmbyers/archive/2005/02/08/369646.aspx"&gt;alluded&lt;/A&gt; to the fact that Eiffel makes use of additional features in the CLR generic support, that C# and VB do not.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In Eiffel, generic types are always covariant (and so have the same sort of run-time checks as arrays).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If you were to look at the &lt;A href="http://msdn.microsoft.com/net/ECMA/#Working Draft 2.9.1"&gt;draft v2 ECMA specification&lt;/A&gt;, you would see the following:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Text style="MARGIN: 0in 0in 0pt 25pt"&gt;&lt;FONT size=2&gt;In addition, CLI supports covariant&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;and contravariant&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;generic parameters, with the following characteristics:&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 61pt; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo2; tab-stops: list 61.0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;·&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;It is type-safe (based on purely static checking) &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 61pt; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo2; tab-stops: list 61.0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;·&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;Simplicity: in particular, variance is only permitted on generic interfaces and generic delegates (not classes or value-types) &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 61pt; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo2; tab-stops: list 61.0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;·&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;Languages not wishing to support variance can ignore the feature, and treat all generic types as non-variant. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 61pt; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo2; tab-stops: list 61.0pt"&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;·&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;Enable implementation of more complex covariance scheme as used in some languages, e.g. Eiffel.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;Contravariance is the opposite of covariance – it means that the subtype relationship of the generic type varies inversely with the relationship of the type parameter.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Or formally, G&amp;lt;T&amp;gt; is a subtype of G&amp;lt;U&amp;gt; if and only if U is a subtype of T. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;This is a pretty cool approach in my opinion.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It allows a compiler to mark generic type parameters on an interface as being nonvariant, covariant or contravariant, and then enforces that those types are used only in places where they are safe (i.e. don’t require a run-time type check).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Specifically, it’s always safe to use a covariant type as an output (return type or out parameter), and a contravariant type as an input.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In IL, covariant type parameters are indicated by a ‘+’, and contravariant type parameters are indicated by a ‘-‘ (non-variant type parameters are the default, and can be used anywhere).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Consider this simple example (using a theoretical extension of C#) from the draft ECMA spec [Update: switched to the newly announced C# 4.0 syntax]:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;// Covariant parameters can be used as result types&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;interface&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: teal"&gt;IEnumerator&lt;/SPAN&gt;&amp;lt;&lt;FONT color=#0000ff&gt;out&lt;/FONT&gt; T&amp;gt; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;T Current { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;bool&lt;/SPAN&gt; MoveNext();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;// Covariant parameters can be used in covariant result types&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;interface&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: teal"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;FONT color=#0000ff&gt;out &lt;/FONT&gt;T&amp;gt; {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;IEnumerator&lt;/SPAN&gt;&amp;lt;T&amp;gt; GetEnumerator();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;// Contravariant parameters can be used as argument types&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;interface&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: teal"&gt;IComparer&lt;/SPAN&gt;&amp;lt;&lt;FONT color=#0000ff&gt;in &lt;/FONT&gt;T&amp;gt; { &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;bool&lt;/SPAN&gt; Compare(T x, T y);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt 0.5in"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;}&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;This would mean we could write code like the following:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt; stringCollection = ...;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;&amp;gt; objectCollection = stringCollection;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;foreach&lt;/SPAN&gt;( &lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt; o &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; objectCollection ) { ... }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;IComparer&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;object&lt;/SPAN&gt;&amp;gt; objectComparer = ...;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;IComparer&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;&amp;gt; stringComparer = objectComparer;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;bool&lt;/SPAN&gt; b = stringComparer.Compare( "x", "y" );&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;But we couldn’t do the opposite – try and convert an IEnumerable&amp;lt;object&amp;gt; to an IEnumerable&amp;lt;string&amp;gt;, or try and convert an IComparer&amp;lt;string&amp;gt; to an IComparer&amp;lt;object&amp;gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In those cases, we’d get a compile time error telling us such a conversion wouldn’t be type-safe.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Of course, languages (like Eiffel) are free to build their own run-time type checking on top of the strict CLR support to relax the rules where they see fit.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;In my opinion this sort of language feature would occasionally be very useful (although the real scenarios would, of course, be much more involved than the above simplistic examples).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;There have been a couple of times when writing real-world C# code when I knew I could write simpler code if the CLR generic variance support was exposed in C#.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Generic variance support in C# has been &lt;A href="http://lab.msdn.microsoft.com/productfeedback/ViewFeedback.aspx?FeedbackID=ea80309b-bb88-4bd3-af35-07dae204287b" mce_href="http://lab.msdn.microsoft.com/productfeedback/ViewFeedback.aspx?FeedbackID=ea80309b-bb88-4bd3-af35-07dae204287b"&gt;discussed&lt;/A&gt; on the MSDN product feedback center, and I don’t think the C# team has ruled it out for a future addition to the language (but of course I don’t know their plans any better than you do).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Although I think this is a cool feature, I don’t think I’m going to start writing any applications in IL just so I can take advantage of it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, it would probably be a fun project to write or extend and existing free C# compiler (like Mike Stall’s &lt;A href="http://blogs.msdn.com/jmstall/archive/2005/02/06/368192.aspx" mce_href="http://blogs.msdn.com/jmstall/archive/2005/02/06/368192.aspx"&gt;Blue&lt;/A&gt;) with support for generic variance.&amp;nbsp; If you're interested in more details (including a thorough description of assignment compatibility in the face of generic variance) see the &lt;A href="http://msdn.microsoft.com/net/ECMA/#Working Draft 2.9.1"&gt;draft v2 ECMA specification&lt;/A&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;[Update: Added details about covariant arrays from Jim Miller's CLI book, and pointer to the draft v2 ECMA spec above.]&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;[Update: See my post "&lt;A href="http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx" mce_href="http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx"&gt;More on generic variance&lt;/A&gt;" for more details and discussion]&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;[Update: Here's an MSDN article that discusses this as well: &lt;A href="http://msdn2.microsoft.com/en-us/library/ms228359(vs.80).aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms228359(vs.80).aspx&lt;/A&gt;]&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN-CA"&gt;[Update: Anders has &lt;A class="" href="http://channel9.msdn.com/pdc2008/TL16/" mce_href="http://channel9.msdn.com/pdc2008/TL16/"&gt;finally announced&lt;/A&gt; that &lt;A class="" href="http://code.msdn.microsoft.com/csharpfuture" mce_href="http://code.msdn.microsoft.com/csharpfuture"&gt;C# 4.0&lt;/A&gt; and the BCL will support generic variance with "in" and "out" keywords.&amp;nbsp; This has been in the works for awhile, and of course I'm super excited about it.]&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=375079" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/rmbyers/archive/tags/Languages/default.aspx">Languages</category><category domain="http://blogs.msdn.com/rmbyers/archive/tags/CLR/default.aspx">CLR</category></item></channel></rss>