Deal with it or don't

Obvious Methods: IDictionary Get – With Defaults plus

This is a follow-up to my post Obvious Methods: IDictionary Get – with defaults

Now the methods will add to the list, if you want.

public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
		                                    TKey key, Func<TKey, TValue> getDefaultValue,
		                                    bool addDefaultToSource = false)
	TValue value;
	if (dictionary.TryGetValue(key, out value))
		return value;

	value = getDefaultValue(key);
	if (addDefaultToSource)
		dictionary.Add(key, value);
	return value;

public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key,
		                                    Func<TValue> getDefaultValue, bool addDefaultToSource = false) { return dictionary.Get(key, k => getDefaultValue(), addDefaultToSource); } public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue, bool addDefaultToSource = false) { return dictionary.Get(key, k => defaultValue, addDefaultToSource); } public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, bool addDefaultToSource = false) { return dictionary.Get(key, k => default(TValue), addDefaultToSource); }

Check out Obvious Methods: IDictionary Get – with defaults for how to use it.


Get User Identity in your log4net

You want your website’s log4net logs to have the authenticated user’s name. Here’s all you do.

(credit to Gian Marco Gherardi)

Add this in your code (right after you call XmlConfigurator.Configure(…) would be fine.)

	GlobalContext.Properties["user"] = new HttpContextUserNameProvider();


	public class HttpContextUserNameProvider
		public override string ToString()
			HttpContext context = HttpContext.Current;
			if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
				return context.User.Identity.Name;
			return "";

The, in your log4net config, you can use it with “%property{user}”
like so…

<conversionPattern value="%date %-5level %property{Category} [%property{user}] - %message%newline" />

Like a charm.

Obvious Extension Method: Left for strings… with Ellipsis!

Substring() is fun, right? It’s fun because “Index and length must refer to a location within the string.”

Well, sometimes, you just want the Left few characters. Sometimes, if you chop of the extra length in your string, you want ellipsis to indicate there are missing pieces.

Here you go:

  1. public static class StringExtensions
  2. {
  3.   public static string Left(this string value,
  4.               int length,
  5.               OverflowBehavior overflowBehavior = OverflowBehavior.None)
  6.   {
  7.     var substring = value.Substring(0, Math.Min(length, value.Length));
  8.     return (overflowBehavior == OverflowBehavior.Ellipsis &&
  9.             length < value.Length) ? substring + “…” : substring;
  10.   }
  11. }
  12. public enum OverflowBehavior
  13. {
  14.   None,
  15.   Ellipsis
  16. }

Now, you can use it like so:

“I’m just saying bless your heart.”.Left(14, OverflowBehavior.Ellipsis) will return “I’m just sayin…”

It defaults to ‘None’, so you can just do “I’m just saying bless your heart.”.Left(14) and get “I’m just sayin”

Obvious Extension Method: ToTitleCase for strings

Got data that’s all upper case? All lower case? Want it title case, or proper case?

  1. using System.Globalization;
  2. public static class StringExtensions
  3. {
  4.     public static string ToTitleCase(this string value)
  5.     {
  6.         var textInfo = new CultureInfo(“en-US”, false).TextInfo;
  7.         return textInfo.ToTitleCase(value.ToLower());
  8.     }
  9. }

“WHY AM I SHOUTING?”.ToTitleCase() returns “Why Am I Shouting?”

“the meek shall inherit the earth.”.ToTitleCase() returns “The Meek Shall Inherit The Earth.”

Obvious Extension Method: TakeAllButLast

I had a previous post about TakeAllButLast, but here’s a more succinct version which also has a callback for the untaken records.

Basically, Linq provides us with the extension method Take(x) to get the first x items in an enumerable. It also gives us Skip(x) to take all but the first x items. There is no “TakeAllButLast(x)” or “SkipLast(x)” equivalent.

public static class EnumerableExtensions
    public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> items, int count, Action<T> onUntaken = null)
        if (items == null)
            throw new ArgumentNullException("items");

        if (count < 0)
            throw new ArgumentOutOfRangeException("count");

        var buffer = new Queue<T>(count + 1);

        foreach (var item in items)

            if (buffer.Count == count + 1)
                yield return buffer.Dequeue();
        if (onUntaken != null)
            foreach (var x in buffer)


You’d use this like this example where you’re processing a file that has ONE Trailer record:

using (var reader = new StreamReader(_inputFile))
    var fileLines = reader.GetLines().TakeAllButLast(1);

…which also uses my GetLines method for a TextReader.

And now, with the callback, you can take a peek at the last line that it skipped:

using (var reader = new StreamReader(_inputFile))
    string lastLine;
    var fileLines = reader.GetLines().TakeAllButLast(1, line => lastLine = line);

Obvious Extension Method: TextReader GetLines()

I don’t know about you, but looping through a TextReader or StreamReader looks ugly to me. I’d rather have the lines of the file returned as an IEnumerable<string>

So here it is. Easy Schpeasy.


  1.     public static class TextReaderExtensions
  2.     {
  3.         public static IEnumerable<string> GetLines(this TextReader streamReader)
  4.         {
  5.             string fileLine;
  6.             while ((fileLine = streamReader.ReadLine()) != null)
  7.             {
  8.                 yield return fileLine;
  9.             }
  10.         }
  11.     }

Now the code using it looks like this:

  1.             using (var reader = new StreamReader("someFile.txt"))
  2.             {
  3.                 foreach (var fileLine in reader.GetLines())
  4.                 {
  5.                     //pretty!
  6.                 }
  7.             }

…and you can use all your favorite Linq on there!

Obvious Extension Methods: The Simple Join

Maybe you just want to know the things from list1 where they have a match in list2.

You can do that yesterday and today with list1.Join(list2, item1=>item1, item2=>item2, (item1,item2)=>item1);

But today and tomorrow, you can simply do list1.Join(list2).

Obvious, right?

  1. public static class Extensions
  2. {
  3.     public static IEnumerable<T> Join<T>(this IEnumerable<T> outer,
  4.         IEnumerable<T> inner)
  5.     {
  6.         return outer.Join(inner, a => a, b => b, (a, b) => a);
  7.     }
  8. }

Maybe it’s not you. Maybe – just maybe – it IS your camera.

I read several photography blogs. One thing that several of these authors keep saying is, “The camera doesn’t matter.” Now I agree whole heartedly when they say something to the effect of “There’s no substitute for an artist’s eye”, but to say that the camera doesn’t matter is going too far.

There IS no substitute for a good eye. Remember that I said that.

Some of these guys just like to think that they are Ivan Lendl out there playing tennis with a wooden racket, still taking the younger players to school with their space-age rackets made with flubber-imbedded Kevlar.  They say things like, “Your equipment does not affect the quality of your image,” and they tell you stories about how this one guy made award winning photographs with nothing but a fifteen dollar Holga. Imagine someone telling Michael Jordan, “Why do you want a basketball? You know, to be a world-class athlete, all you really need is a wooden tennis racket.  Ivan Lendl did it!”

So you see, in my analogy, the photographer is not just like a tennis player picking his tools for returning serves and volleying. It’s bigger than tennis. It’s all sports. He’s an athlete picking a tool that will not only work on grass and clay, but on hardwood and ice … many different conditions. He’s not just getting tennis balls thrown at him. He’s getting tennis balls, basketballs, and boxing gloves thrown at him – and he has to use his broom to sweep the ice in front of the big round sliding stone… for some reason.

My point is, for some things, all you need is a Holga or a cell phone camera. Likewise, for some sports all you need is a racket. For others, you need a bat, a glove, and some metabolic steroids. Landscape photography has different needs than taking pictures at a dimly lit dance recital. Macro photography has different needs from taking long-exposure shots of fireworks.

What if you want to make an award winning photo, but all you have is a cell phone? Well you are limited to what kind of photos you can get. (Keep remembering that I said that there’s no substitute for a good eye.) You better want your award to be for a photo taken in the bright daylight. You want to control your depth of field? Sorry. You better want your award to be for a photo with a large depth-of-field because you can’t control that.

Want to make an award-winning photo using a Holga? You’d better (have the eye of an artist, and) want some wicked vignetting.

You’d better want to play tennis, because you have a tennis racket.

“Your equipment does not affect the quality of your image” is just simply a ludicrous thing to say, and quite frankly, diminishes all the rest of the authors’ arguments.  If you want people to believe you when you say, “there’s no substitute for an artist’s eye”, then don’t include that on a page where you also say that the equipment has absolutely no effect on the quality of the image.

You want to know another famous person who also said, “your equipment does not affect the quality of your image?” Adolf Hitler. See? All my arguments just fell flat because I went too far and said something that is (almost) certainly not true. These authors have a good message, but they spoil it with crazy proclamations and bad analogies about painters and piano players and their equipment.

An aside:

Speaking of bad analogies – back to Ivan Lendl for one more… These cameras-make-no-difference authors are also often the guys who dismiss techniques like HDR and other post-processing magic. It’s in-camera, or it’s cheating to these guys. When they look at photos from Trey Ratcliff, I can just imagine a look on their faces like the top-ranked Ivan Lendl had when seventeen-year-old Michael Change, suffering from cramps, served underhanded to win the point in the 1989 French Open. Lendl looked at the judges afterward with a look that seemed to say, “that had to break SOME rule, right?”

So don’t feel bad that you framed a shot beautifully, but you can’t get that tiny-depth-of-field effect that you want. It might not be you. It might be your camera. Don’t feel bad that you masterfully used the light to illuminate a beautiful portrait, but you can’t capture what’s in your mind’s eye with your 1990’s era webcam. It might not be you. It might be your camera.

Sorry Wayne Gretzky. Your tennis games sucks. But not just because you aren’t a tennis player. It’s also because hockey sticks make horrible tennis rackets.

Obvious Extension Methods: IEnumerable Cache

So you don’t want to do a ToList(), but you don’t want to enumerate your IEnumerable<T> more than once? How about an extension method called “Cache” that Caches the output as you go.

  1. public static class Extensions
  2. {
  3.     public static CachedEnumerable<T> Cache<T>(this IEnumerable<T> enumerable)
  4.     {
  5.         return new CachedEnumerable<T>(enumerable);
  6.     }
  7. }
  8. public class CachedEnumerable<T> : IEnumerable<T>
  9. {
  10.     IEnumerator<T> _originalEnumerator;
  11.     readonly IEnumerable<T> _originalEnumerable;
  12.     readonly List<T> _cache = new List<T>();
  13.     public CachedEnumerable(IEnumerable<T> enumerable)
  14.     {
  15.         _originalEnumerable = enumerable;
  16.     }
  17.     public IEnumerator<T> GetEnumerator()
  18.     {
  19.         foreach (var t in _cache)
  20.         {
  21.             yield return t;
  22.         }
  23.         if (_originalEnumerator == null)
  24.         {
  25.             _originalEnumerator = _originalEnumerable.GetEnumerator();
  26.         }
  27.         while (_originalEnumerator.MoveNext())
  28.         {
  29.             _cache.Add(_originalEnumerator.Current);
  30.             yield return _originalEnumerator.Current;
  31.         }
  32.     }
  33.     IEnumerator IEnumerable.GetEnumerator()
  34.     {
  35.         return GetEnumerator();
  36.     }
  37. }

That’s it. If you want to see it in action, open LINQPad, select Language: “C# Program”, delete everything, paste in the above, then finally, paste in the below:

void Main()
  var x = GetNumbers().Cache();

  "TAKE 2.".Dump();

  "Get them all.".Dump();

  "Get them all again.".Dump();

public IEnumerable<T> GetNumbers()
  yield return 1.Dump("Numbers is hard");
  yield return 2.Dump("Numbers is hard");
  yield return 3.Dump("Numbers is hard");
  yield return 4.Dump("Numbers is hard");
  yield return 5.Dump("Numbers is hard");
  yield return 6.Dump("Numbers is hard");


Dell Chat Log

Dell’s website won’t let you sort their products by things like screen resolution, but luckily, they offer a handy “chat” feature. So I started the chat, and the rest speaks for itself. Below is the “Dell Chat Session Log” (I might have edited some of my spelling mistakes)

Session Started with Agent (Tabassum M)
Agent (Tabassum M): “Hi Philip”
Agent (Tabassum M): “Welcome to Dell US Chat! My name is Tabassum Meraj and I will be your Dell.com Sales Chat Expert.
I can be reached at tabassum_meraj@dell.com or via phone at 1-800-289-3355 ext. 4163264. How can I help you today?”
Philip: “What’s the cheapest laptop dell has with around 1000 lines of resolution on the monitor?”
Agent (Tabassum M): “I would be Glad to assist you with that question”
Agent (Tabassum M): “how many inches of monitor are you looking at ?”
Philip: “It doesn’t matter.”
Philip: “I just want more than 720 lines of resolution.”
Agent (Tabassum M): “give me 2 minutes while I check that for you”
Philip: “ok”
Agent (Tabassum M): “thank you for waiting Philip”
Agent (Tabassum M): “we have Dell IN2030M 20-Inch Flat Panel Monitor with LED that comes with 1600X900 resolution for $159.99”
Philip: “I understand…”
Philip: “But…”
Philip: “My question was…”
Philip: “What’s the cheapest laptop dell has with around 1000 lines of resolution on the monitor?”
Philip: “laptop”
Agent (Tabassum M): “Philip you want the laptop screen with 1000 resolution”
Philip: “Yes. A laptop with a screen that has more than 720 lines of resolution.”
Agent (Tabassum M): “we have XPS 15 with 1080p resolution for $949.99 which is the least expensive one we have”
Philip: “Ah. Ok. thank you.”
Agent (Tabassum M): “How soon are you planning to purchase?”
Philip: “Unsure.”
Agent (Tabassum M): “we have very good deals running I can suggest one as per your needs”
Philip: “good deals on XPS 15 ?”
Agent (Tabassum M): “yes Philip”
Philip: “So they are $949.99 ? or are they actually less than $949.99 ?”
Agent (Tabassum M): “the price is $949.99 I can create quote and see what best deal I can offer you from my side however it will be valid only for today”
Philip: “Because I don’t really want or need the included camera and software. I have all of that already.”
Agent (Tabassum M): “all our laptops come with inbuilt webcam”
Philip: “That’s fine. i’m talking about this: “Includes Canon digital camera and Adobe Photoshop & Premier Elements.””
Philip: “That’s the one that is $999.99 on your website.”
Agent (Tabassum M): “that is on promotion which camera with camera included in the deal we cannot remove it”
Agent (Tabassum M): “would you like to check the deal on the one without camera which is for $949.99”
Philip: “Sure”
Agent (Tabassum M): “can you help me with your phone number to pull your information”
Philip: “Actually, none of MY information will help you determine the price of your products.”
Philip: “Let me know the price.”
Agent (Tabassum M): “Philip I need to create quote to help you with the best deal”
Agent (Tabassum M): “Quote is not a commitment to purchase. But it Is the list of all the specs & also the price so that you can be absolutely clear of what you are getting & paying.”
Philip: “you’re losing the sale… you have my email address.”+B62
Philip: “You do not need my phone number.”
Philip: “you either have a price or you don’t.”
Philip: “If you do. I’m still listening.”
Philip: “If you don’t, then you’re wasting my time.”
Agent (Tabassum M): “the best deal that I can help you with is for $849.99”
Philip: “Is there a link for the computer that is that price?”
Philip: “the list of all the specs?”
Agent (Tabassum M): “Philip the price for the system on website is $949.99 and I need to create quote which will be emailed to you for $849.99 as it is not available online”
Philip: “You emailed it to me? Ok. Great! Thank you!”
Agent (Tabassum M): “Philip to create quote I need your information which will be emailed to you”
Philip: “I don’t need you to email me my information. I already have it. I need you to email me your product information. This is not difficult.”
Philip: “I understand you are following your rules, so I’m iritated at your rules, not you, personally.”
Philip: “I don’t need you to email me my phone number.”
Philip: “I need you to email me the price plus the specs. that’s it.”
Philip: “Can you do that or not.”
Philip: “?”
Agent (Tabassum M): “I understand Philip however this is the procedure to follow for a quote and I can help you with the link where you can check the specs however for the price that I offered it can only be done by quote”
Philip: “fine. SEND ME THE QUOTE!”
Agent (Tabassum M): “Can you help me with your billing and shipping address full name and contact number to create quote for you”
Philip: “Ha ha.”
Philip: “your procedures just lost you the sale.”
Session Ended