Casting and foreach – swings and roundabouts

Sunday, 20 September 2015

I had a good discussion the other day about a code warning that one of the new Roslyn Code Analyzers had flagged.

SonarLint comes from SonarSource, and has a whole bunch of analyzers, including this one: S3217 - "Explicit" conversions of "foreach" loops should not be used.

It is a useful warning, highlighting how the foreach instruction will cast each item for you if the collection of items is not generic. If you only use generic collections, you’ll probably never hit this – but if you ever have to deal with some of the older classes (such as the original ADO.NET types) then this may come up.

This got me curious. What does the IL (intermediate language) look like for a foreach.

The following C# code will trigger this warning:

    var table = new DataTable();

    DataRowCollection rows = table.Rows;

    foreach (var row in rows)
    {

    }

We get this IL:

  IL_0000:  nop
  IL_0001:  newobj     instance void [System.Data]System.Data.DataTable::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance class [System.Data]System.Data.DataRowCollection [System.Data]System.Data.DataTable::get_Rows()
  IL_000d:  stloc.1
  IL_000e:  nop
  IL_000f:  ldloc.1
  IL_0010:  callvirt   instance class [mscorlib]System.Collections.IEnumerator [System.Data]System.Data.InternalDataCollectionBase::GetEnumerator()
  IL_0015:  stloc.2
  .try
  {
    IL_0016:  br.s       IL_0026
    IL_0018:  ldloc.2
    IL_0019:  callvirt   instance object [mscorlib]System.Collections.IEnumerator::get_Current()
    IL_001e:  castclass  [System.Data]System.Data.DataRow
    IL_0023:  stloc.3
    IL_0024:  nop
    IL_0025:  nop
    IL_0026:  ldloc.2
    IL_0027:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    IL_002c:  brtrue.s   IL_0018
    IL_002e:  leave.s    IL_0045
  }  // end .try
  finally
  {
    IL_0030:  ldloc.2
    IL_0031:  isinst     [mscorlib]System.IDisposable
    IL_0036:  stloc.s    V_4
    IL_0038:  ldloc.s    V_4
    IL_003a:  brfalse.s  IL_0044
    IL_003c:  ldloc.s    V_4
    IL_003e:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0043:  nop
    IL_0044:  endfinally
  }  // end handler

I’m no IL guru, but it you can get the basic idea – and sure enough you can see line IL_001e, there’s a castclass operation that’s run for each item in the foreach loop.

So in this case, you can’t just explicitly cast a DataRowCollection to an IList<DataRow>. The LINQ Cast<> extension method can be used though.

This code no longer triggers the warning:

    foreach (DataRow row in rows.Cast<DataRow>())
    {

    }

And here is the corresponding IL:

  IL_0045:  nop
  IL_0046:  ldloc.1
  IL_0047:  call       class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Cast(class [mscorlib]System.Collections.IEnumerable)
  IL_004c:  callvirt   instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator()
  IL_0051:  stloc.s    V_5
  .try
  {
    IL_0053:  br.s       IL_0060
    IL_0055:  ldloc.s    V_5
    IL_0057:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current()
    IL_005c:  stloc.s    V_6
    IL_005e:  nop
    IL_005f:  nop
    IL_0060:  ldloc.s    V_5
    IL_0062:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    IL_0067:  brtrue.s   IL_0055
    IL_0069:  leave.s    IL_0078
  }  // end .try
  finally
  {
    IL_006b:  ldloc.s    V_5
    IL_006d:  brfalse.s  IL_0077
    IL_006f:  ldloc.s    V_5
    IL_0071:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0076:  nop
    IL_0077:  endfinally
  }  // end handler

You can see there’s no more castcall operation, but instead notice line IL_0047. Now instead the code is calling the Cast extension method on the entire enumerable.

You might be wondering, does it make any different to performance? In this case not that I could detect. I loaded up a DataTable with 1,000,000 rows and compared execution times between the two approaches, and there wasn’t any significant difference between them.

This makes sense if you think about it – the cast needs to happen – either up front before the loop, or inside the loop. There’s no avoiding it.

So I’d say this is one warning that you shouldn’t necessarily just blindly follow. Having said that, if you’re iterating over the object more than once, then you probably will see a performance boost if you do the cast up front.

User group audio and video

Friday, 11 September 2015

I’ve been pondering how to improve the ability of ADNUG (Adelaide .NET User Group) to do a decent job at:

I’m not sure if there’s necessarily a huge overlap between those two requirements, but they both involve audio so they’re kind of related.

Microsoft LifeCam StudioFor the recent Google Hangout we had with Scott Hanselman, I purchased a Microsoft LifeCam Studio webcam. I mounted this on a tripod and used a couple of USB extension cables. Scott reported that the video quality was a bit poor with some flickering. I suspect the use of the extension cables might have reduced the quality of the signal too much – combined with the fact that I was only on Wifi instead of using the network cable (that I only noticed when the meeting was almost over!). The tripod mount is definitely a plus though.

Scott recommended the Logitech Webcam 930e, which has the advantage of being wider-angle (90° vs the LifeCam’s  75°). I’ll see how I go with the Microsoft camera, otherwise trading up might be an option.

Sound-wise was also not ideal. I didn’t have any complaints with previous hangouts earlier in the year with Jon Galloway and Sayed Hashimi, but maybe Scott was possibly more interactive and wanted to hear questions raised from and converse with the crowd. As it was, I had to repeat the questions for him (as I was standing near my laptop). So a microphone that can pick up the whole room would be great.

It seems the kind of microphone I’d need to pick up is a a conference or ‘boundary’ type. Most of these are ‘omni-directional’, meaning they pick up sound in all directions and from a wide area – contract that with a normal vocal mic, which works best right in front of your mouth.

For a USB solution, these models from MXL seem to be well regarded:

MXL AC404 USB Conference Microphone

MXL Mics AC-424 USB Boundary Microphone (MXL AC-424)

For an XLR connector (XLR is the 3-pin connector commonly used with professional audio equipment), then maybe something like this:

Samson CM11B Omnidirectional Boundary Microphone

The meeting we had this week at Marcellinas had over 40 people in attendance. It turns out Marcellinas function room has their own PA system, so I was glad to make use of that so that everyone could hear better. Having said that, they just have a hand-held microphone with no mic-stand – so that can get tricky if you’re speaking and trying to type at the same time.

Having a mic and loud speaker was a big help to the people in the room, but I didn’t have time beforehand to see if I could hook into their amplifier to record the audio.  Instead to make the audio recording of the meeting, I just used the Windows 10 Voice Recorder app on my laptop (using my laptop’s inbuilt microphone), and just left that running for the duration of the talks.

A lapel microphone would be ideal, and wireless even better (so you’re free to walk around). 

Audio2000 AWM-6032UL UHF Dual Channel Wireless Microphone System with One Handheld & One Lapel (Lavalier) Mic. This kit with a wireless hand-held and lapel would be pretty nice – wire up the main presenter with the lapel, which leaves the hand-held for the MC.

I get the impression that if you got the XLR-type microphones, you really need some kind of mixer/pre-amp that you’d then feed into the laptop (or other recording device).

Something like one of these:

So who knows if we ever get any of this. Given the costs, most of it’s probably just a pipe-dream. Having said that I’d appreciate any thoughts/suggestions/feedback on the options above or other ways that we might take some ‘baby-steps’ to improve things just a little bit.

Windows detected a hard disk problem

Wednesday, 26 August 2015

I found this when logging in this morning:

Windows dialog

And some related events in the System event log:

Log Name:      System
Source:        Microsoft-Windows-DiskDiagnostic
Date:          26/08/2015 9:20:08 AM
Event ID:      1
Task Category: None
Level:         Critical
Keywords:     
User:          SYSTEM
Computer:      *****
Description:
Windows Disk Diagnostic detected a S.M.A.R.T. fault on disk ST500DM002-1BD142 (volumes D:\).  This disk might fail; back up your computer now. All data on the hard disk, including files, documents, pictures, programs, and settings might be lost if your hard disk fails.  To determine if the hard disk needs to be repaired or replaced, contact the manufacturer of your computer.  If you can't back up (for example, you have no CDs or other backup media), you should shut down your computer and restart when you have backup media available.  In the meantime, do not save any critical files to this disk.

Log Name:      System
Source:        disk
Date:          26/08/2015 9:20:07 AM
Event ID:      52
Task Category: None
Level:         Warning
Keywords:      Classic
User:          N/A
Computer:      *****
Description:
The driver has detected that device \Device\Harddisk0\DR0 has predicted that it will fail. Immediately back up your data and replace your hard disk drive. A failure may be imminent.

Log Name:      System
Source:        iaStorA
Date:          26/08/2015 9:04:54 AM
Event ID:      4102
Task Category: None
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      *****
Description:
Error log: Smart event occured on disk :S2AXWXVT 

Fortunately, this is my D: drive. There’s only a couple of virtual machines there, but nothing I can’t recreate if necessary. That’s the first time I’ve seen hard disk SMART diagnostics kick in like that.

DDD Melbourne 2015

Wednesday, 12 August 2015

Last Saturday I attended the DDD Melbourne conference. I’d decided earlier in the year that I’d like to go along, so it was an extra bonus to learn that I had a session submission accepted too.

Swinburne University with DDD sign

I flew over on the Friday, and stayed at the Pathfinder Motel in Kew (nothing fancy, but it did the job, though the traffic can be a bit noisy). I’d originally looked at the map and figured it was pretty close to the conference venue at Swinburne University’s Hawthorn campus. After I’d settled in to my motel room, I decided to do a bit of reconnaissance of the area and walk down to the campus just to check how long it would take me to get there the next morning.

Map showing route from motel to campusTurns out I probably miss-read the scale on the map, as the round trip turned out to be just short of 8kms. Needless to say I caught the tram on Saturday Smile.

On the plus side, there are lots of cafes, restaurants and a cinema on Glenferrie Rd, so plenty of eating options.


People registering in the morningRegistration officially opened around 8.20am on Saturday, but there were quite a few people there even before that. Lots of helpful volunteers were on hand to help with this as well as general venue management, directing pedestrian traffic and helping with morning/afternoon teas and lunch.


Attendees in main auditorium waiting for startStart of conference

This year they had 398 attendees, and the tickets all sold out in just 33 minutes. Wow!


The keynote speaker was Darrel Miller, who spoke about REST, the journey around making it work and separating the concept of REST from a particular implementation.

Darrel Miller presenting with photo of a Poutine

He likes food, so almost all of his slides used food metaphors.

Lucky the organisers laid out some morning tea next before the first session began!

Sarah presenting her talk

First off, I saw Sarah Tabrizi speak about “Agile and Azure”. She had some great Azure demonstrations. I actually liked that the demos were pre-recorded as it meant they all worked properly (no surprises or problems with dodgy network connections) and could be talked over the top of as required.


Philip presenting

Next up I caught Philip Beadle discussing tips on automation. Definitely some Lean influences coming through there.

Some of the key points Philip made were:


Daniel presentingNext Daniel Chambers spoke about making your C# and JavaScript more functional. No surprises that last year Daniel presented on F#!

He suggested that functional languages were the next evolution after object-oriented languages. I asked him what came next, but he wasn’t sure.

Some interesting demos on incorporating functional concepts into C# (via Linq and Reactive Extensions) and JavaScript (via lodash). His talk materials are here.

I’m also embarrassed to admit that I was confused by Daniel’s Twitter picture. He doesn’t look anything like Jack Nicholson.


People in foyer eating lunch

Time for some lunch. Hotdogs with cheese and onions, and drinks/muffins etc.


James Newton-King presenting

Next up, James Newton-King on designing good APIs. James knows a thing or two about this, being the developer behind JSON.NET – one of the most depended upon 3rd-party libraries available for .NET.

Some very interesting reflections from him on things to consider (and watch out for) when designing your own APIs.


And then, it was my turn!

Room full of attendees waiting for my talk to beginMe (David) presenting my talk

As you can see, the room was packed. As a speaker, there isn’t much more of a complement than that (especially as everyone stayed to the end!). My talk seemed to go quite well, though I need to practise my chocolate throwing technique.

(Second photo courtesy of Martin Doms)

 


Paul Stovell speaking about his company

The final speaker for the day was Paul Stovell, founder of Octopus Deploy.

I’ve bumped into Paul a few times over the years (he’s originally from SA, though now based in Brisbane), so it was great to hear his story of how he created the Octopus Deploy software application and then build a successful company around that product.


Final 'thankyous' from Lars KlintThen after a final thankyou from Lars (one of the organisers), it was off to the pub around the corner for free drinks (make mine a dry ginger, thanks)

People at the pub

It was a great conference. Really good speakers, content and organisation.

I made a particular point of talking to a number of the speakers to see if we could get them to present to the Adelaide .NET User Group in the future. I also spent a bit of time talking to Lars about how they’d organised the event, to get ideas about maybe doing a DDD Adelaide again in the future. It was great how helpful and encouraging he and others I spoke to were.

The final big news was that NDC (who were the main sponsors of the conference) announced that they will be holding a conference in Australia 1-5th August 2016. NDC Sydney is now open for registration, and also has a call for papers open until April 1st. At least they’ve given everyone a year to save up for it.

ASP.NET Web API for .NET Framework 4 in Visual Studio 2015

Tuesday, 11 August 2015

This is a pretty unique set of constraints I know – sometimes there are limitations outside your control as to which version of .NET you (or those who will be running your software) can use.

Note that the most recent version of Web API that works with .NET Framework 4.0 is 4.0.30506.0 (The 5.x releases all require at least .NET 4.5)

  1. Open Visual Studio 2015
  2. Create a new project (Make sure you select .NET Framework 4 in the frameworks dropdown list) Visual Studio New Project dialog
  3. Open the Package Manger Console
  4. Enter Install-Package -Id Microsoft.AspNet.WebApi -Version 4.0.30506 -DependencyVersion HighestMinor
  5. Update-Package Newtonsoft.Json
  6. (Optional) Install-Package -Id Microsoft.AspNet.WebApi.Tracing -Version 4.0.30506
  7. Add an App_Start folder
  8. Inside this folder, add new class WebApiConfig
  9. Add the following content to the WebApiConfig class:
public static void Register(HttpConfiguration config)
{
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new
        {
            id = RouteParameter.Optional
        }
    );

    // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
    // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
    // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
    //config.EnableQuerySupport();

    // To disable tracing in your application, please comment out or remove the following line of code
    // For more information, refer to: http://www.asp.net/web-api
    config.EnableSystemDiagnosticsTracing();
}
  1. In the top-level of the project, add a Global.asax file
  2. Open the Global.asax.cs file and add the following method:
protected void Application_Start()
{
    WebApiConfig.Register(GlobalConfiguration.Configuration);
}
  1. Add a Controllers folder
  2. Inside the Controllers folder, add a new class (eg. ValuesController)
  3. Update the ValuesController class to look as follows:
public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    public void Delete(int id)
    {
    }
}

Your project should look similar to this:

Solution Explorer showing Web API project

You can now build and run the web application and browse to /api/Values and get a response from your controller (JSON or XML depending on your browser)