XYZCONSULTING

4/7/2010

Sorting a .Net List with Lambdas

I love linq.  I would wager that most developers who have done much with it share a similar love.

It makes our lives easier.  It eliminates writing copies amounts of loops, parsing xml, interacting with databases, you name it.  It’s great.

 

When I run into a situation where linq does not have an obvious tie in, I start to get a little anxious,  (pathetic I realize).

 

Today I was faced with a situation where I had a list of custom classes that I needed to sort. 

This being a list, OrderBy was nowhere to be found.

 

So, I returned to my roots and started writing a compare for my class so that I could use the Sort command that is part of the List generic type.  That is when it struck me that I could probably accomplish this using a lambda.  It turns out that I was correct.  Lambda’s were a perfect fit for this scenario.  The code remained clean and concise and I was saved having to write additional methods just to accomplish a one-off scenario on what was a otherwise complete project.

 

Lamdas are a progression in C# past anonymous methods.  In the code below, I show how the code would be implemented with separate function, an anonymous method and finally, with a Lambda expression.

 

First, the test class that we’ll be working with:

public class MyClass
{
    public int propA { get; set; }
    public int propB { get; set; }
    public int propC { get; set; }
}

Our test class:

public class Tester
{
    public void Main()
    {
        List list = new List();
        list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
        list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
        list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
        list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });        
    }
}

Now then, we write a custom comparer.  Not a lot of code, but you can imagine how this extrapolates over various properties for large classes.

public class Tester
{
    private static int CompareByPropA(MyClass a, MyClass b)
    {
        return a.propA.CompareTo(b.propA);
    }
    public void Main()
    {
        List list = new List();
        list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
        list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
        list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
        list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });

        //Using the comparer built into the MyClass method
        list.Sort(CompareByPropA);        
    }
}

This time, we drop the custom comparer and implement the sort using an anonymous method.

public class Tester
{
    public void Main()
    {
        List list = new List();
        list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
        list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
        list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
        list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });

        //Using an anonymous method
        list.Sort(delegate(MyClass a, MyClass b) { return a.propA.CompareTo(b.propA); });
    }
}

Finally, we rewrite the anonymous method into a Lambda.  It is still easy to read and much more concise.

public class Tester
{
    public void Main()
    {
        List list = new List();
        list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
        list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
        list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
        list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });

        //Using a Lambda
        list.Sort((a, b) => a.propA.CompareTo(b.propA));
    }
}

So, next time you go to write custom compare code, step back and see if you can do it a little more simply.  If you are going to be using your comparison code in more than one place, then perhaps it is still a better idea to implement it using that route vs the lambda.  If it is a one-off thing, then a lambda and some linq can be a beautiful thing!

3/17/2010

OData = Hotness

Microsoft has officially announced OData.  If you are not aware of what this is, then in a sentence: OData is a queryable REST based interface that exposes your data via AtomPub.

 

To publish a feed, you have to use .Net.  However, they have provided client sdk’s for a variety of languages to allow for simple querying of the exposed services and they are working on several more.

 

I strongly encourage you to check it out.

 

Partly to give an idea of what is possible, and partly for my own reference, I am going to repost a “cheat sheet” that I found online at Meta-Me

 

 

The Service:

It all starts with a Data Service hosted somewhere:

http://server/service.svc

 

Basic queries:

You access the Data Service entities through resource sets, like this:

http://server/service.svc/People

You request a specific entity using its key like this:

http://server/service.svc/People(16)

Or by using a reference relationship to something else you know:

http://server/service.svc/People(16)/Mother

This asks for person 16’s mother.

Once you have identified an entity you can refer to it’s properties directly:

http://server/service.svc/People(16)/Mother/Firstname

 

$value:

But the last query wraps the property value in XML, if you want just the raw property value you append $value to the url like this:

http://server/service.svc/People(16)/Mother/Firstname/$value

 

$filter:

You can filter resource sets using $filter:

http://server/service.svc/People?$filter=Firstname  eq ‘Fred’

Notice that strings in the filter are single quoted.

Numbers need no quotes though:

http://server/service.svc/Posts?$filter=AuthorId eq 1

To filter by date you have identity the date in the filter, like this:

http://server/service.svc/Posts?$filter=CreatedDate eq DateTime'2009-10-31'

You can filter via reference relationships:

http://server/service.svc/People?$filter=Mother/Firstname eq 'Wendy'

The basic operators you can use in a filter are:

Operator

Description

C# equivalent

eq

equals

==

ne

not equal

!=

gt

greater than

>

ge

greater than or equal

>=

lt

less than

<

le

less than or equal

<=

and

and

&&

or

or

||

()

grouping

()

There are also a series of functions that you can use in your filters if needed.

 

$expand:

If you want to include related items in the results you use $expand like this:

http://server/service.svc/Blogs?$expand=Posts

This returns the matching Blogs and each Blog’s posts.

 

$select:

Some Data Services allow you to limit the results to just the properties you require – aka projection – for example if you just want the Id and Title of matching Posts you would need something like this:

http://server/service.svc/Posts?$select=Id,Title

You can even project properties of related objects too, like this:

http://server/service.svc/Posts?$expand=Blog&$select=Id,Title,Blog/Name

This projects just the Id, Title and the Name of the Blog for each Post.

 

$count:

If you just want to know how many records would be returned, without retrieving them you need $count:

http://server/service.svc/Blogs/$count

Notice that $count becomes one of the segments of the URL – it is not part of the query string – so if you want to combine it with another operation like $filter you have to specify $count first, like this:

http://server/service.svc/Posts/$count?$filter=AuthorId eq 6

This query returns the number of posts authored by person 6.

 

$orderby:

If you need your results ordered you can use $orderby:

http://server/service.svc/Blogs?$orderby=Name

Which returns the results in ascending order, to do descending order you need:

http://server/service.svc/Blogs?$orderby=Name%20desc

To filter by first by one property and then by another you need:

http://server/service.svc/People?$orderby=Surname,Firstname

Which you can combine with desc if necessary.

 

$top:

If you want just the first 10 items you use $top like this:

http://server/service.svc/People?$top=10

 

$skip:

If you are only interested in certain page of date, you need $top and $skip together:

http://server/service.svc/People?$top=10&$skip=20

This tells the Data Service to skip the first 20 matches and return the next 10. Useful if you need to display the 3rd page of results when there are 10 items per page.

Note: It is often a good idea to combine $top & $skip with $orderby too, to guarantee the order results are retrieved from the underlying data source is consistent.

 

$inlinecount & $skiptoken:

Using $top and $skip allows the client to control paging.

But the server also needs a way to control paging – to minimize workload need to service both naive and malicious clients – the OData protocol supports this via Server Driven Paging.

With Server Driven Paging turned on the client might ask for every record, but they will only be given one page of results.

This as you can imagine can make life a little tricky for client application developers.

If the client needs to know how many results there really are, they can append the $inlinecount option to the query, like this:

http://server/service.svc/People?$inlinecount=allpages

The results will include a total count ‘inline’, and a url generated by the server to get the next page of results.

This generated url includes a $skiptoken, that is the equivalent of a cursor or bookmark, that instructs the server where to resume:

http://server/service.svc/People?$skiptoken=4

 

$links

Sometime you just need to get the urls for entities related to a particular entity, which is where $links comes in:

http://server/service.svc/Blogs(1)/$links/Posts

This tells the Data Service to return links – aka urls – for all the Posts related to Blog 1.

 

$metadata

If you need to know what model an OData compliant Data Service exposes, you can do this by going to the root of the service and appending $metadata like this:

http://server/service.svc/$metadata

This should return an EDMX file containing the conceptual model (aka EDM) exposed by the Data Service.

3/27/2009

Response.Redirect inside of a Try/Catch

Ok, first off, let me state, that I am not entirely certain WHY I did this in the first place.  I am going to say I was rushed and wasn’t thinking clearly.  However, I glazed over it and moved on and when it came time to test, I was getting bizarre behavior that didn’t throw an error.

Session[“var”] = “”; 

try 
{ 
    Session[“var”] = “Good Value”;

    Response.Redirect(“newpage.html”); 
} 
catch(Exception ex) 
{ 
    Session[“var”] = “Bad Value”; 
}

In the code above, Session[“var”] will ALWAYS equal “Bad Value”.  Why you may ask?

Response.Redirect throws a ThreadAbortException.  … Fun, no?

If you are building a URL inside of a try block that you want to then redirect to, declare a string, build your url, and then pass that on to the Response.Redirect statement. 

For Example:

string _url;

try 
{ 
    _url = “yourpage.aspx?var=” + iffyMethodCall(); 
} 
catch(InvalidOperationException ex) 
{ 
    _url = “error.html”; 
}

Response.Redirect(url);

So, If you ever run into odd behavior in a site you are working on and when debugging, your code goes straight past your Response.Redirect and into the catch block and the debugger starts giving you cryptic messages, this may be what you’re seeing.

3/21/2008

WPF: Element State Binding

I've been working with WPF lately.  Partly for work, but mostly to teach myself while at the same time being productive.  I am definitely one of those people that learns best by doing.

I have been working on adding some encryption to a application recently and I am making a form that will allow the user to enter a password that will be used for the encryption/decryption process.

encrypt.jpgOn the form that I made, I had a checkbox to determine whether they even want to use encryption at all, as well as two password boxes for the password and the confirmation.  I wanted to make it such that when they clicked the checkbox that it would enable the password fields and disable them when the checkbox was unchecked.  Essentially tie the IsEnabled property of the PasswordBox's to the IsChecked property of the CheckBox.  

Well, I could tie a method to the Checked event of the CheckBox, and then adjust the PasswordBoxes accordingly, or I could do it the WPF way and use Binding to tie the elements together to one another.

Opting for the latter (since I am trying to learn after all), I dug around in my WPF book and in short order, had the answer.

Assuming that the CheckBox is named checkbox1:

<PasswordBox Name="Password1" Margin="0,5" Width="200"
IsEnabled="{Binding ElementName=checkbox1, Path=IsChecked}"/>

What is happening here is that WPF is telling the IsEnabled property to watch checkbox1 and specifically the IsChecked property of that control and grab the value from there.

Pretty cool stuff.

5/7/2007

Silverlight Airlines

There are a lot of great examples of what Silverlight is going to be capable of. Silverlight Airlines is just one among many. Check out David Anson blog on it which includes a live link and of course full source code! Also, be sure to head over to Lutz's site and check out several of the samples that he has written as well.

5/1/2007

Silverlight, CoreCLR, DLR, oh My!

Wow... so lots has been going on lately. Adobe is trying to encroach on Microsoft's turf with Apollo and in reply, here comes Silverlight. Now, Silverlight by itself is alright. I am not going to profess that it is going to kick Flash to the curb by any means. To be honest, it has a ways to go before it will be a major competitor against the offering that Adobe already has out there. However, given that Flex is still being adopted for RIA development if Microsoft focuses their efforts with Silverlight to that front, then they will most likely succeed. They will succeed due to the sheer mass of people developing against their technologies. The big announcment that a lot of people seem to be overlooking in the big Flash vs. Silverlight debate is that beneath Silverlight lies something so massive that it could change things all by itself. CoreCLR. CoreCLR is a trimmed down CLR with all the goodies of the larger .Net Framework that runs cross platform. So what? Microsoft has done some cross platform stuff in the past and ditched it. I don't see that happening in this case however. I think Microsoft is finally starting to come around on the fact that Windows, while holding a massive amount of the market share, is not the end-all-be-all when it comes to things like... the internet. Microsoft is realizing that it is time to start competing against people like Adobe/Macromedia who have ruled the internet for quite a while now, who have gotten so cocky with their market share on the internet side of things that they have started working toward a desktop takeover. The other nice little inclusion with Silverlight is the DLR or Dynamic Language Runtime. The DLR allows Ruby, Python and other traditionally NON-.Net languages to be compiled into IL code so that they can utilize the CLR. This is being done with respect to the language as well. i.e. Microsoft is not trying to assert their way of doing things into these community run languages, but rather are taking the accepted ways of doing things and incorporating those into the DLR. If that wasn't enough, Microsoft has released the DLR to the community so that it can be built upon and more languages can be added in over time. There are too many things to list here and to be honest, since I am not at Mix and am relying on News and Blog Postings to get all of my information, I am going to quit writing for the time being and go continue reading. I would highly recommend reading Scott Hanselman's post on the subject though I leave you with this: It is going to be interesting to watch what happens over the next year, between Adobe and Microsoft, things are going to move even further off of the desktop and this is going to cement the RIA into the mainstream environment. I am not going to say that one technology is better than the other at this point and I am going to concentrate on learning both Flex/Apollo and Silverlight/WPF over the next few months so that I can be proficient in both, because much like the battle between BlueRay and HD-DVD, this is just getting started. Just don't write Microsoft off because they are behind. They aren't the underdog by any means. They've been sitting back and watching, silently plotting, and they've just made their move.