Wednesday, July 11, 2012

Distinct on custom objects in datatables and lists

I use this blog a lot to make notes for myself so that I don’t … umm… what’s the word?

Anyway, here’s some of the latest notes that caused me a research headache. Maybe it will save you a headache, or maybe I’ll remember to look here the next time my headache starts.

Suppose you have a data table in C#.
Let’s say it has a date time and a custom object (type = “myclass”).
The “myclass” thing is simple – it’s just a class with one property “v” which is a DateTime (I’ll plug that in later) and the code to set up and load the table is here:

DataTable dt = new DataTable("sometable"); 
DataColumn dc = new DataColumn("someDate", typeof(DateTime));
 dt.Columns.Add(dc);
 dt.Columns.Add(new DataColumn("someObj", typeof(myclass))); 
List l = new List(); for (int i=0;i<10; i++) 
    DataRow dr = dt.NewRow();
    dr[0] = DateTime.Now; 
    myclass m = new myclass();
    m.v = DateTime.Now.ToString();
    dr[1] = m;
    dt.Rows.Add(dr); l.Add(m); 

So we end up with a table with two columns: one is a DateTime and the other is a myclass. Conceptually, the DateTime and the myclass objects are about the same thing.
You head shouldn’t hurt yet. If it does, maybe you should stop now. But get the aspirin ready:
var n = (from p in dt.AsEnumerable() select p["someDate"]).Distinct();
This is good. Walk through a foreach on n and it gives one instance for every unique date. In theory, each value in the table is distinct because it’s a DateTime and the loop iteration takes a fraction of a second. In practice, the code is so fast, that the runtime engine eats the fraction of a second, and you’ll get one unique entry in n, so your foreach will have one loop iteration. My head is still pain free. Until I do this:
var n = (from p in dt.AsEnumerable() select p["someObj"]).Distinct();
Now the “Distinct” acts on the custom objects and you get 10 items in n. The headache is small, though, because I get that .Net doesn’t know how to compare my custom objects. So it can’t distinct them. MSDN says that myclass needs to implement IEquatable. There are some examples out there that seem to work.
For simplicity, let me the load 10 custom objects into a List, rather than a data table, and I’ll modify myclass to implement IEquatable.
public class myclass: IEquatable

public object v;
public override string ToString()
{
return v.ToString();
}
public override int GetHashCode()
{
return v.GetHashCode();
}
public bool Equals(myclass other)
{
return true;
}
}

I already snuck the List into the code above, so I can use it (cuz I’m sneaky like that).

So I can do:
var lc = (from pp in l
select pp).Distinct();

And this is *supposed* to call the “GetHashCode()” on the custom objects to do the distinct…. But it doesn’t. If you loop through lc, it will give you 10 iterations.

The good news is that I can add a IEqualityComparer to the mix:
class TheComparer:IEqualityComparer
{
public bool Equals(myclass x, myclass y)
{
return true;
}
public int GetHashCode(myclass m)
{
return m.v.GetHashCode();
}
}

Now if I set the EqalityComparer to the Distinct() on the list, it seems to work: TheComparer c = new TheComparer();

var lc = (from pp in l
select pp).Distinct(c);

Yay! So I should be able to apply the same EqualityComarer to the data table’s Distinct() and it should work, right? var mmm = (from p in dt.AsEnumerable() select p["someObj"] ).Distinct(c);

Nope. Not only doesn’t this work, it gives a *compile error*. This is where I got into some really serious aspirin. Turns out that this statement returns a result of IEnumerable, while the previous one returns IEnumerable. They’re both generics that implement IEnumerable, so they support the same methods, right? Not exactly.

The EqualityComparer has to be type cast. If you look at the definition, it is bound to a type. So, even though a DateTime is an object, creating an EqualityComparer with an object type GenericComparer:IEqualityComparer And then trying to use it on a Distinct() for a List will throw a compiler error.

Took me around a day to figure all this out and the solution. The solution is to type cast the Linq:

var mm = ((IEnumerable)(from p in dt.AsEnumerable()
select p["someObj"] as myclass)).Distinct(c);

Note that the only real difference between this and the code above is that I typecast IEnumberable with my custom object. But now, I don’t get a compiler error. Also note that this will not compile unless I also typecast the select.
*NOW* the Distinct will correctly accept and use the EqualityComparer and it can call the Equatable methods on the incoming objects to do the compare.

So far, this is the only way I’ve found to do a Distinct() on a DataTable with custom objects. Microsoft’s internal DataTable (non-Linq) methods don’t like custom objects at all. In fact, they pretty much ignore them.

Next time I’ll probably have a section on how to use custom object in data tables and bind to databound grids dynamically.

--kevin

Thursday, June 14, 2012

The biggest news from Apple.

I’m not an Apple fan-boy exactly, but I do respect the company and am constantly impressed by them. I’ve learned never to bet against them, especially in my stock portfolio.
So I’ve been keeping an eye on the latest news from their developer’s conference, and I think one story has been under-told.

This one.

Auto week reported this. For the most part, the mainstream media (and even the tech community) has been ignoring it.

Let me summarize, to save you the time of reading: Apple has agreements to put Siri in the cars made by these auto makers: BMW, GM, Mercedes, Jaguar, Audi, Toyota, Chrysler and Honda.

Ford already has a tight relationship for voice control software with Microsoft. Besides Ford, Apple gets…um… everyone else? OK, Hyundai and Ferrari aren’t in the list, but come on, everyone else is.

This is a big fat hairy deal for Apple. And a big, fat, hairy coup. Microsoft was really the first one to do this. They pioneered the trail and owned the market with Ford. And then Apple just stole it from them – not one or two other potential clients – but *all* the rest. I mean, what were the MS sales guys doing while Apple was pitching this? Were they off trying to flirt with Siri?

I think it’s a big, fat, hairy hit for Microsoft. OK, it’s a small hit for Google, too, but Google is only loosing what it never really had – not being a real player in this market anyway. But Microsoft… man… talk about shutting down an entire part of the business! Sure, they’ll hang onto Ford for a while, but how long before Apple gets that? How long before someone wants the same voice system in their Lincoln that their friends have in the Beemers? And even if they keep Ford, the growth potential of the market is gone .

And think about what this means for Apple. While all the world has been cursing or praising Windows 8 and MS is paddling hard to catch up in the ARM space (or is it ARMs race?), Apple flanked them big. Think about it. Think about what happens if you get used to Siri in your car giving you directions to a new Sushi place. That means extra revenue for Apple. It means add dollars from the Sushi place. It means integration with Apple’s new maps (take *that* Google). It means integration with Facebook and Open Table (they announced that too, by the way) so you can see if your friends liked the Sushi place and make a Siri-based reservation on the way. And it means a new reliance on Siri. So, if you are on a trip and you rent with Hertz, you’ll want Siri. If you are at home and you’re wondering where to grab dinner, you‘ll want Siri. It means getting people so used to the service that they’ll look for it everywhere.

And what amazes me, again, is that Microsoft invented the market, but just didn’t have the ability to capitalize on it. Microsoft is the true innovator here (something they claim to do more than they really do). But – most likely—Apple is the true winner.

Now, I wish I wouldn’t have sold that Apple stock…..
--kevin

Monday, June 4, 2012

Debugging tricks

I was sitting with someone the other day and watching him debug an application and it made me want to post a couple tricks with the debugger that can help. 

first: learn some of the simple shortcuts. F5 starts the app with debugging ctrl+F5 starts it without. I was surprised by the fact that he took his hands off the keyboard to look for the mouse so that he could click the little icon on the toolbar every time he wanted to run something.

F9 sets (and clears) breakpoints – this is probably the handiest thing--  and F11 will “step into” a method, while F10 will step over it.
Those are the basics.

In addition, you can go to view->other windows->command window in Studio and have access to all the debugger info (and then some). A couple of the most useful things are:

        “Debug.DisableAllBreakpoints” and “Debug.EnableAllBreakpoints”. These alone are so useful, it’s scary. On any complex application, you know, the one that you’ve been working on for the last 3 days without coming up for air, you’ve got lots of steps to do before you get to the “good stuff”. Once you do actions X + Y, you want to step through loop Z to see what it’s doing. But you don’t want to step through Z until you’ve done X and Y. So you can end up stepping through lots of code that you really don’t care about. But if you disable all breakpoints, then run, do X and Y, then Enable all breakpoints, you will fly right past your breakpoints until you need them. Very cool.



      typing ? followed by a variable (there needs to be a space between the ? and the variable name) will print the contents of the variable. This is basically the same as hovering over the variable with your mouse or doing a quick watch, but typing it is easier when you’re looking for someArray[i].someObject.someProperty . I’ve seen lots of people spend all day trying to “drill down” in hover over without clicking on the wrong thing and making it vanish. I do it too, but the debug command is way easier. 

 
      Also, remember conditional breakpoints. When you set a break point, you can right click on it and select “condition”. This will open a dialog that will allow you to enter whatever you like and stop only when the condition is true. So, you can break on the 321st iteration of the loop without having to step through the first 320. 

.  Hope this all helps. Please list some of your favorites below. 
-    --kevin

Friday, June 1, 2012

Extension methods



Yay! I finally have an excuse to use extension methods.
First, a brief explanation of what they are. Suppose you have an object – say a string. And you want to add some functionality to it. You could subclass the object (assuming it’s not sealed) and add your new method.

But if all you want to do is add one tiny little method, subclassing seems a bit top-heavy, doesn’t it? Besides, unless you’re using an object factory pattern (my favorite design pattern, by the way), you face the prospect of finding and changing every object instantiation in every line of code of your project to replace the parent with the child class. On large, multiple developer projects, this gets rough.

Microsoft gives you a work around. What you can do is to add a special static method somewhere in your code and .Net will automagically assign this to the desired class.

For example,
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ''.''?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
The magic is the keyword “this” in the method signature. “This” tells the compiler that “WordCount” is an extension method on the string object.
The end result is that your code can now do something like:

       string x = "this is a test string";
       Console.WriteLine(x.WordCount());

And the Console will show the word count of x, just as if “WordCount” was a public method on the string class.

I’ve thought this was cool for a long time, but couldn’t find a use for it.

But, Dmytrii Nagirniak posted a reply to a thread on Stack Overflow that provides an awesome use:

http://stackoverflow.com/questions/1725903/determine-if-datacolumn-is-numeric

To sum it up, .Net has no “IsNumber()” method. So looking at a potential data value, it’s really hard to know if it’s a number type. What you end up with, is a complex if statement that does a GetType(), but then has to check to see if the type is a Double OR a Single OR an Int32 OR an Int64 OR a UInt16 OR…. Etc.

Putting this into an extension method makes a ton of sense. (I’m not sure why Microsoft didn’t already do this, frankly). This means that developers don’t need to deal with this mess each time, but just have to call
x.IsNumber().

The code for the extension just looks like this:
  public static Type[] numericTypes = new[] { typeof(Byte), typeof(Decimal), typeof(Double),
        typeof(Int16), typeof(Int32), typeof(Int64), typeof(SByte),
        typeof(Single), typeof(UInt16), typeof(UInt32), typeof(UInt64)};
 
 public static bool IsNumber(this object x)
    {
        if (x == null)
            return false;
      
        return numericTypes.Contains(x.GetType() );
    }

And this allows  you to instantiate any object and define whether the object is a number type.

A second (useful) variation of this examines whether a DataColumn (ie, in a DataTable) is a number type. It’s different because the DataColumn.GetType() would just return “DataColumn, you moron”, so you have to look at “DataColumn.DataType” :
  public static bool IsNumeric(this DataColumn col)
    {
        if (col == null)
            return false;
        return numericTypes.Contains(col.DataType);
    }


Pretty cool stuff.
--kevin

Friday, May 25, 2012

Addons

I've added a few extensions to Visual Studio that I thought I'd point out. By way of disclosure, I'm using Studio 2010 Professional, so these may or may not work with anything else.

First:
Power Productivity Tools from Microsoft

This is the coolest and most useful plug in I've found. You can follow the link above to see what it does in detail, but it includes things like auto brace completion, a couple improvements to quick find and a really nice improved scroll bar that allows you to see all break points and bookmarks on the scroll bar. Best of all, you can turn each feature on and off individually.So if all you want is to be able to cntr-click to go to the definition (very handy, by the way) you can shut the rest down.

Next:
Power Commands
This one is a bit less useful for me, but still has some nice things. The ability to "open containing folder" so you can get to the Windows Explorer location of the file is, itself, enough of a reason to get this. "Open Command Prompt" also ranks up there, since it will not only open the prompt, but auto-navigate you to your project folder.

Finally:
Indent Guides
This is a must have! It basically draws little colored lines connecting every open brace to its corresponding close brace. So it makes it much easier to debug a nested if inside of a loop inside of a method inside a class inside a name space and actually *understand* it.


Other things:
Keyboard shortcuts
Microsoft has made some of the keyboard shortcuts available as a poster.
Some of my favorite lesser-known ones:
  • F12 on anything will take you directly to its defintion
  • ctrl and the minus sign ( - ) is like a "back" button in a browser and will return to your last location. So if you put a cursor on a method reference, then hit F12, you'll be at the method definition. If you then type ctrl-, you'll be "back" to the place where you originally put your cursor.
  • ctrl+shift+-  () will move you forward -- like a "forward" button in a browser. 
  • Ctrl+shift+b does a build of the current project. 
Hope this all helps you be more productive. I think I deserve a cookie now.
--kevin

Thursday, May 17, 2012

Another Little C# Thing I didn't know


Sometimes I don't think I know much about C# (or anything else for that matter).

I didn't know you could do this:
static void two(string x, int num=1)


in this, the parameter "num" is optional. I didn't know you could optional parameters in C#. I've been looking at C# code since C# has been around -- code reviews, my own code, samples on the internet -- but I can't recall ever seeing anyone use this.

Here's a code sample.
        static void Main(string[] args)
        {
            two("one", 2);
            two("two");
        }
 
        static void two(string x, int num=1)
        {
            Console.WriteLine(x + " " + num);
        }
 
 
You can also used named parameters. So this also works:
        two(num:7, x :"named");
(at least in .Net 2.0 and later).
I remember named and optional parameters in VB4,
but I was completely clueless that you could do it in C#.

Now, we're all a tiny bit less clueless.
--kevin

Wednesday, May 2, 2012


Quick diversion to Skyrim            

OK. Here’s a geek thing: I like to play computer games sometimes. Occasionally, I give into my guilty pleasure until it becomes an obsession. Naturally, I often keep my obsession hidden, like any good addict.

But I have to blog my recent experience with Skyrim, because I think it says a lot about the industry.

When my Skyrim disk arrived from Amazon, I eagerly popped the DVD into the drive and salivated during its loading. Only, you can’t just install a PC game anymore. The only way you can play (well, without a lot of back-door things) is to install Steam. For the non-gamers out there, Steam is an online service that verifies that I really own the copy of Skyrim I’m playing. Now forget the fact that Skyrim sold 3.5 million copies in the first 48 hours after its release and sold something around 10 million copies total, the companies that make this stuff now want to make sure that some poor 14 year old in Iowa isn’t playing illegally and costing them the 10 million and *first* copy they could have sold, so they burden the other 10 million of us with this top-heavy, internet-based nonsense.

(Example of the nonsense : I can’t play Skyrim if my internet connection goes down, even though I paid my $50 for the game and it’s not an online game. It’s kinda like OnStar preventing you from starting your car unless you first tell them your password. If you happened to park in an underground garage, too bad. You’ll have to be towed. Oh and Steam launches at start up every time I boot. There’s no option to turn that off without digging through a bunch of registry keys—which I did, by the way. Without doing that, every time you boot, you have to wait for the dialog to come up and prompt for your password, after it finishes verifying that the Steam service is available on the internet.)

I told myself last time I played a Steam game that I would never do it again. Seems I lied to myself. Well, to be fair, it wasn’t obvious that Skyrim used Steam. I think I’d heard it at one point, but forgot it. So, it is what it is.

Steam added quite a while to the install. It has to connect to the internet and sign you in with your account. Of course, I couldn’t remember my Steam password. I mean, it’s not like I use it all the time or have it tattooed on my arm or anything. So after a half an hour of installing and resetting and such, I was in.

Once I was in, Steam started to advertise to me – because, clearly, 10 million sales isn’t enough. Mostly, they advertise downloadable content, but occasionally, they push new games.
I get that I watch commercial TV and have to watch the ads because I don’t pay for it. And I get that I have to pay for HBO so that I don’t see the commercials. But when I pay for something *then* also have to watch the commercials, it fries my cupcakes.

OK. So I’m in and have seen all the ads. Now the game starts in earnest. The default settings on the game came up with lower-than-acceptable resolution, but I changed that. The game also came up in full screen mode, which I hate. I multi-task. I’m typically playing a game like this while I’m surfing the web, updating facebook, checking email and chatting with a friend. So I re-set the full screen to “windowed” mode – only to discover that the game was obviously written for an Xbox, since the window had no controls on it, and was just about impossible to drag. Oh, and it was on the wrong monitor. It always comes up on my primary, even though I set it for the secondary. Because, of course, Xboxes only have one monitor, I guess.

I figured out a trick to drag the window (had to place another app over it, so that just the outside of the frame was shown, then select the overlay-ed window and slide the mouse up until I just hit the exposed part of the frame. Then I could drag... no, really).

Well, a pain, but functional. So the game comes up and is just about *unplayable* with a mouse and keyboard. Oh, there’s instructions on how to do it, but the interface is completely unmanageable. Because it was made for an Xbox -- with its Xbox gamepad -- not a PC.

I remembered that I had an old Logitec game pad, so I shut down the game and searched for my controller. Got it, plugged it in and re-started the game. Only, Steam (God love them) re-set all my graphics settings and opened the game full-screen on the wrong monitor again, after trying to upsell me, of course. (*sigh*).

Well, OK, fine-- only the game doesn’t see my controller at all. I Google. And find out that the *only* control the game will support is the Xbox controller, because—wait for it -- it was written for the Xbox. I Google some more and find an emulator that will translate my Logictec controller into Xbox-ese, and fake out the game into thinking it’s an Xbox one.  So, I swallow the virus risk (well, I did scan the file), run the emulator and I’m good.

I restart Skyrim, sign into Steam and wait for Steam to respond. Steam re-sets my video again and opens full-screen on the wrong monitor with the low video settings. Then it tries to upsell me. But the emulator works.

So I’m gaming now. Although I spent so much time messing with it that I haven’t actually gotten into the game much. It’s playable now. But, so far, it’s not much fun. Hopefully, after $50 and a few hours of my time, that will change.

But all this speaks to the computer industry. The company that makes Skyrim (Valve, I think?) made something like half a billion dollars from the game. But it isn’t enough money anymore to avoid ads, to allow people to run offline or to actually support the target platform.

I see the same thing in other software I buy. The general quality sucks – I don’t mean functionality, I mean the platform support and such. Windows 8 looks like a kludge (more on that later). We’re told that we need a new interface because the old interface won’t support notepads – even though I don’t have a notepad… because the zillion dollars they make from PCs isn’t enough. The new version of Office (so I hear) will incorporate Office 365’s online support, even though I do a lot of editing offline. My new Dell gets angry when I don’t synch with Dell’s online cloud, even though I have no interest in putting anything on their online portal.

Seems to me, it’s all part of the same deal in computers to drive more review from the products. We’re being pushed into products that we’re told we want because it’s beneficial for the companies that make them. We’re having our personal data sold. We’re getting advertised to on our own computers.

Of course, we’re the ones who keep buying the stuff.
--kevin