Omer van Kloeten's .NET Zen

Programming is life, the rest is mere details

News

Get Firefox

Locations of visitors to this page

.NET Resources

Articles :: CodeDom

Articles :: nGineer

Culture

Projects

A Limitation of Lambda Expressions and Overloaded Extension Methods

Picture by Roger Ferrer Ibáñez, Some Rights Reserved (CC-NC-SA)Tamir hates lambdas. He was having a problem with one of his lambda expressions and twittered about it. Around that time I opened my twitter account (yes, Yosi finally convinced me) and offered my help.

He wanted to have a single extension method that could iterate over a collection and either change or keep the values it got. Kind of like this:

items.ForEach(item => item.SubItems.ForEach(subItem => subItem = newValue));

Where ForEach was defined as:

static void ForEach<T>(this IList<T> collection, Action<T> action)
{
    for (int i = 0; i < collection.Count; i++)
    {
        action(collection[i]);
    }
}

This did not work simply because subItem is a local variable - a copy of either the reference (when using a Reference Type) or of the value itself (when using a Value Type) - the lambda expression was (very loosely) translated to the following:

void Foo(SubItem subItem)
{
    subItem = newValue;
}

What I then tried to do was to replace Action<T> with a delegate with a ref parameter, so that the local variable will change. It turns out lambda expressions can not contain ref parameters.

On to the next solution - overloading the ForEach extension method:

static void ForEach<T>(this IList<T> collection, Action<T> action)
{
    for (int i = 0; i < collection.Count; i++)
    {
        action(collection[i]);
    }
}

static void ForEach<T>(this IList<T> collection, Func<T, T> action)
{
    for (int i = 0; i < collection.Count; i++)
    {
        collection[i] = action(collection[i]);
    }
}

This way, one can now write the following:

items.ForEach(item => item.SubItems.ForEach(subItem => newValue));

The first call (outer ForEach) will use the overload with Action<T> and the second (inner ForEach) will use the Func<T, T> overload and end up changing the current subItem. The C# compiler does a nice job finding the best overload to call.

Linq to SQL: ChangeConflictException With "WHERE 0 = 1"

I just finished debugging a very annoying error, where I kept getting a ChangeConflictException with the message "Row not found or changed" while trying to update my data. I found that there were no Member Conflicts in the exception, which seemed really weird to me.

When I set the Log property on my context, I found that Linq to SQL was using UPDATE statements that looked like this:

UPDATE [dbo].[MyTable]
SET [Col1] = @p0, [Col2] = @p1
WHERE 0 = 1
-- @p0: Input ...
-- @p1: Input ...

This was apparently some optimization made by the Linq to SQL team, but it gave me a clue as to where to look.

Apparently, when you have a Linq to SQL object model that differs by even one property from your database, you're prone to get this. I found out that two of my fields that were in the SET part of the WHERE clause were defined as NOT NULL in my object model, but were marked as nullable in my database model. Quick fix and all works well.

One has to wonder why there is no "Synchronize" button in the Linq to SQL designer.

Also, here's an interesting piece of code I wrote while debugging, which serializes a ChangeConflictException to string:

public static string SerializeForLog(this ChangeConflictException e, DataContext context)
{
    StringBuilder builder = new StringBuilder();

    using (StringWriter sw = new StringWriter(builder))
    {
        sw.WriteLine("Optimistic concurrency error:");
        sw.WriteLine(e.Message);

        foreach (ObjectChangeConflict occ in context.ChangeConflicts)
        {
            Type objType = occ.Object.GetType();
            MetaTable metatable = context.Mapping.GetTable(objType);
            object entityInConflict = occ.Object;

            sw.WriteLine("Table name: {0}", metatable.TableName);

            var noConflicts =
                from property in objType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                where property.CanRead &&
                      property.CanWrite &&
                      property.GetIndexParameters().Length == 0 &&
                      !occ.MemberConflicts.Any(c => c.Member.Name != property.Name)
                orderby property.Name
                select property;

            foreach (var property in noConflicts)
            {
                sw.WriteLine("\tMember: {0}", property.Name);
                sw.WriteLine("\t\tCurrent value: {0}", 
                    property.GetGetMethod().Invoke(occ.Object, new object[0]));
            }

            sw.WriteLine("\t-- Conflicts Start Here --", metatable.TableName);

            foreach (MemberChangeConflict mcc in occ.MemberConflicts)
            {
                sw.WriteLine("\tMember: {0}", mcc.Member.Name);
                sw.WriteLine("\t\tCurrent value: {0}", mcc.CurrentValue);
                sw.WriteLine("\t\tOriginal value: {0}", mcc.OriginalValue);
                sw.WriteLine("\t\tDatabase value: {0}", mcc.DatabaseValue);
            }
        }

        sw.WriteLine();
        sw.WriteLine("Attempted SQL: ");

        TextWriter tw = context.Log;

        try
        {
            context.Log = sw;
            context.SubmitChanges();
        }
        catch (ChangeConflictException)
        {
            // This is what we wanted.
        }
        catch
        {
            sw.WriteLine("Unable to recreate SQL!");
        }
        finally
        {
            context.Log = tw;
        }

        sw.WriteLine();

        sw.WriteLine(e.SerializeForLog());
    }

    return builder.ToString();
}
Linq: FirstOrFallback

Sometimes you want to use FirstOrDefault, but the default value of T is a valid value that might get returned. If you used FirstOrDefault, you wouldn't know whether the value that you got is a valid first or the default fallback. I use FirstOrFallback to explicitly specify which fallback value I want, rather than always use default(T):

public static T FirstOrFallback<T>(this IEnumerable<T> enumeration, T fallback)
{
    // Check to see that enumeration is not null
    if (enumeration == null)
        throw new ArgumentNullException("enumeration");

    IEnumerator<T> enumerator = enumeration.GetEnumerator();

    enumerator.Reset();

    if (enumerator.MoveNext())
        return enumerator.Current;

    return fallback;
}

On a side note: I realize most of the extension methods I post here are pretty obvious, but I love sharing time-saving code. :)

Linq Extensions Release 2 Now on CodePlex

I've updated my long standing Linq Extensions project on CodePlex to .NET 3.5 RTM and added the latest extension methods.

You can open bugs and feature requests using the Issue Tracker. If you want to download it, go and download the source code directly.

Linq: The Missing ToDictionary Extension Method Overload

Enumerating over a Dictionary<TKey, TValue> you will get structs of type KeyValuePair<TKey, TValue>. Whenever you use the ToDictionary extension method, you are forced to specify how to get the key and value for each item, even if it's an enumeration of KeyValuePairs. Seems a bit redundant, doesn't it?

public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> enumeration)
{
    // Check to see that enumeration is not null
    if (enumeration == null)
        throw new ArgumentNullException("enumeration");

    return enumeration.ToDictionary(item => item.Key, item => item.Value);
}

Well, that little bit of code settles that. :)

Linq: SequenceSuperset

Here's another Linq method I wanted to share. This one takes two enumerations, enumeration and subset and checks to see whether subset exists in enumeration in its original order. I used the naming convention set by SequenceEqual.

Examples:

  1. enumeration = (1, 2, 3, 4, 5); subset = (3, 4) ==> SequenceSuperset(enumeration, subset) = true
  2. enumeration = (1, 2, 3, 4, 5); subset = (6, 5) ==> SequenceSuperset(enumeration, subset) = false (6 does not exist in enumeration)
  3. enumeration = (1, 2, 3, 4, 5); subset = (3, 5) ==> SequenceSuperset(enumeration, subset) = false (3 is never immediately followed by 5 in enumeration)
  4. enumeration = (1, 2, 3, 4, 5); subset = (5, 4) ==> SequenceSuperset(enumeration, subset) = false (5 is never immediately followed by 4 in enumeration)

And here's the code:

public static bool SequenceSuperset<T>(this IEnumerable<T> enumeration, IEnumerable<T> subset)
{
    return SequenceSuperset(enumeration, subset, EqualityComparer<T>.Default.Equals);
}

public static bool SequenceSuperset<T>(this IEnumerable<T> enumeration,
IEnumerable<T> subset,
Func<T, T, bool> equalityComparer) { // Check to see that enumeration is not null if (enumeration == null) throw new ArgumentNullException("enumeration"); // Check to see that subset is not null if (subset == null) throw new ArgumentNullException("subset"); // Check to see that comparer is not null if (equalityComparer == null) throw new ArgumentNullException("comparer"); using (IEnumerator<T> big = enumeration.GetEnumerator(), small = subset.GetEnumerator()) { big.Reset(); small.Reset(); while (big.MoveNext()) { // End of subset, which means we've gone through it all and it's all equal. if (!small.MoveNext()) return true; if (!equalityComparer(big.Current, small.Current)) { // Comparison failed. Let's try comparing with the first item. small.Reset(); // There's more than one item in the small enumeration. Guess why I know this. small.MoveNext(); // No go with the first item? Reset the collection and brace for the next iteration of the big loop. if (!equalityComparer(big.Current, small.Current)) small.Reset(); } } // End of both, which means that the small is the end of the big. if (!small.MoveNext()) return true; } return false; }
Help! My Web Application Throws an Insane Amount of TypeLoadExceptions!

One of the first things I noticed when I started debugging our web application was that at load I got an insane amount of these:

A first chance exception of type 'System.TypeLoadException' occurred in System.Web.dll
A first chance exception of type 'System.TypeLoadException' occurred in System.Web.dll
A first chance exception of type 'System.TypeLoadException' occurred in System.Web.dll
...

After digging into the code, I found out that during the loading process of controls, ASP.NET tries to find the type that matches a certain tag. The following code piece from System.Web.UI.NamespaceTagNameToTypeMapper (line 82):

Type type = null; 

// If loading the type from the assembly depends on a referenced assembly that cannot
// be loaded, we should throw the actual exception, instead of later reporting a more
// generic error saying the type was not found (Devdiv 138674) 
try {
    type = _assembly.GetType(typeName, true /*throwOnError*/, true /*ignoreCase*/); 
} 
catch (System.IO.FileNotFoundException) {
    throw; 
}
catch (System.IO.FileLoadException) {
    throw;
} 
catch (BadImageFormatException) {
    throw; 
} 
catch {
    // For all other exceptions, such as when the type is not present in the assembly, 
    // we ignore the exception so that we can continue to check other assemblies to look
    // for the type.
}
return type;

What the hell?! This is a horrible bottleneck!

What's the solution, you ask? Well, it's simple - just tell ASP.NET ahead of time where your controls are with the @ Register directive. For instance:

<%@ Register Assembly="System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" 
             Namespace="System.Web.UI.WebControls" TagPrefix="wc" %>

This gives ASP.NET a little hint, telling it that if it wants controls with the wc tag prefix, it should look for them in the System.Web.UI.WebControls namespace in the System.Web assembly. Then all you have to do is to mark all of the controls that come from that namespace in that assembly with that specific prefix, as such:

<wc:Literal ID="Something" runat="server"></wc:Literal>

And that's that. No more annoying exceptions.

Make sure to use the full assembly name in the @ Register directive, otherwise you'll get a System.IO.FileNotFoundException thrown when ASP.NET can't find the assembly.

One more thing that's important to note is that if you have only a few of these, set your web.config's compilation element's batch attribute to false, which means ASP.NET will load pages on demand. This way you'll know the culprit page when you hit it for the first time, rather than have the exception thrown when the whole application starts.

[Update: An application-wide solution would be to use the system.web / pages / controls element in the web.config to declare prefixes for all of your controls, rather than at the single page level:

<configuration>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="wc" namespace="System.Web.UI.WebControls"
assembly="System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>

And thanks to Ofer Bar from my team for the tip.]

Tech-Ed Israel 2008

[This is a summarization post for my international audience; For a more complete coverage, see my and many other bloggers' impressions at Microsoft Israel's blogosphere]

This week, the biennial Tech-Ed Israel conference took place in Eilat. I was fortunate enough to be sent there, as a blogger, along with 25 others, on Microsoft's dime. Nice.

I've gone ahead and written quite a few posts about it on my (mostly) Hebrew blog, almost all of them from the conference itself, but I've decided to write down some of my impressions here as well:

  • This was the first time I was ever at a Tech-Ed, and it was a blast. Too bad it was only three days.
  • There was a ton of swag being handed out and a special kit was given to each blogger (including some extension cords and cables for our laptops, so we don't go without ;) ).
  • On the organizational level, most of the things seemed to tick like clockwork, something which is far from obvious. Unfortunately, lectures constantly starting late and ending late soured the event. Wireless Internet connectivity was, however, almost everywhere, which is very cool and relatively new to Microsoft's conferences in Israel.
  • Although the level of the lectures was high most of the time, it was as if some of the lectures were very shallow and only touched the surface of the material they were about (though a couple were far from that). As someone who is very in-tune with what's going on technology-wise at Microsoft, I was disappointed by the fact that most of the lectures had no added value for me.
  • There were no surprises, when it came to technology. Microsoft's newfangled release cycle, with alphas, betas and CTPs galore is good for the product, but it's killing the ability to show innovation at conferences. Everything is out there already, just waiting to be discovered by the public themselves. When we're talking about the near future, I can see Rosario is about to suffer the same fate.
  • It was a pleasure to mix and mingle with people from all over the country who were into exactly what you were doing. For me that meant meeting a lot of people I know, from close friends to people I haven't seen in years: in a country of seven million, 3,500 people from the industry are a lot. :)
    Also, I found out Ido was engaged to be married this November! Mazal Tov, man!
  • Each time slot always had between 5 and 17 concurrent lectures, which had the potential to require me to clone myself to get to every one that I wanted to go to, but ended up with me defaulting to play Guitar Hero III on the XBox 360 stands (more on that in a bullet) when I found that none of the lectures in certain time slots tickled my fancy. Only once was I torn between going to one of two lectures. That's a pretty big achievement, and not a good one at that.
  • There were two XBox 360 stands with big-assed screens, one of which constantly had Guitar Hero III playing, a game I fell for, won a prize at with Lior (woohoo) and whose soundtrack I continued humming for the remainder of the week. I had a blast playing.
    However, that was a bit odd, since to date no one is officially importing it to Israel. Yes, you heard right - there were two stands with game consoles no one can officially buy in the country. When would XBox 360 get the official Microsoft Israel seal of approval? Sometime around 2006. You get big points on marketing the units, Microsoft, but none for actually selling any.
  • Eric Rudder was there. I hadn't noticed. On the other hand, I did get a chance to talk to Lisa Feigenbaum and Luke Hoban, both of whom were really nice and a great conversation.
  • Yosi Taguri (who works with me at NuConomy) and Lior Zoref from Microsoft Israel accompanied the conference with their video podcast, Yosi and Lior's Experimental Broadcasts. They had some really funny skits and a cool see-through studio in the middle of the action to broadcast their interviews from. It was very cool and, although I can't be certain, was also a nice touch for those who didn't get to go to the conference.
  • The traditional second-night party was awesome, but I think the guys at Microsoft Israel were a little on the defensive after what happened in 2006, when there was too much alcohol and not enough non-alcoholic beverages (so much so that everyone was dead drunk by 3am and Luca Bolognese went up on the stage the next day hung over, only to receive the best score given to a lecturer in that Tech-Ed), so that all of the alcohol ran out an hour into the party. Hope they overcompensate for that in 2010. ;)
  • When I got home, I started reading through the 350+ blog posts about the conference (did I say 25 bloggers got a free pass?) and found out there were lots more things I simply missed, such as a real life Formula 1 car with a Formula 1 simulator in it and a stand featuring some of Microsoft Research's products. The only thing missing from that was a Surface. :)

So why is this post here, on my English blog? Well, there are two reasons:

  1. See how much fun we had?
  2. You should come next time! :D
Visual Studio Feature Request: Generic Constraints Auto-Complete

I'd love to see this become a reality in the next version of Visual Studio:

Linq: ContainsAtLeast and AggregationOrDefault

I've created a couple of useful extension methods that I like to use with Linq, so here they are:

ContainsAtLeast

I've noticed that there's no way to find out whether a collection has at least X items. The following takes the collection, tries to take X items from it and asks whether it succeeded or not:

public static bool ContainsAtLeast<T>(this IEnumerable<T> enumeration,
int count) { // Check to see that enumeration is not null if (enumeration == null) throw new ArgumentNullException("enumeration"); return (from t in enumeration.Take(count) select t) .Count() == count; }

AggregationOrDefault

When I need the first item in a collection, I love using First when I need an exception and FirstOrDefault when I don't. However, this doesn't exist for aggregations and if your collection is empty, Max, Min, etc. will throw an exception.

public static T AggregationOrDefault<T>(this IEnumerable<T> enumeration,
Func<IEnumerable<T>, T> aggregationMethod) { // Check to see that enumeration is not null if (enumeration == null) throw new ArgumentNullException("enumeration"); // Check to see that aggregationMethod is not null if (aggregationMethod == null) throw new ArgumentNullException("aggregationMethod"); if (!enumeration.ContainsAtLeast(1)) return default(T); return aggregationMethod(enumeration); }

What this does is take a collection and an aggregation method, checks whether there's at least one item and applies the method. This is very useful, because most aggregation methods that take only one parameter - the collection, are not generic, so that would mean, just like in Linq itself, creating a copy of this method for every numeric type (as an example, see Max<T> compared to Max).

How to use it? Simple:

myEnumeration.AggregationOrDefault(Enumerable.Max);

In this case, sending the Max method to AggregationOrDefault.

More Posts Next page »