VS 2008 released

A few days ago Microsoft released Visual Studio 2008.

Thats great news, since with the release of VS 2008, c# 3.0 and .NET 3.5 is released as well.

.NET have some really exiting new features, like

LINQ
Extension methods
and lambda functions

I will take a look at them and make a few examples on how to use each of the those items above.

.NET TimeZone

Everyone working with .NET and TimeZones have at one point thought, why the #%&#&% can't I instantiate another TimeZone than the current one, i.e. why is it not possible to create a .NET TimeZone object in the following simple way.

TimeZone zone = new TimeZone("Europe/Copenhagen");

TimeZone zone = new TimeZone("CET");

It seems like Microsoft did not think of, or decided not to implement multi timezone support in .NET, and thats too bad, because Timezone handling, Daylight savings are just a bitch to work with.

Timezones are not so bad, since its pretty easy to identify what timezone a given country is in. There are numerous sources for this on the internet, such as http://www.timeanddate.com/worldclock/, and with a little manual work, or a little screen scraping you can have a combined country/timezone list in no time.

The real problems occurs when you want to find out whether or not a given TimeDate object is within the Daylight savings time for a given country and timezone, and in that, the timezone are of no use, since it says nothing about the daylight savings of the date.

I have tried some solutions where I try to identify the daylight savings time for the most used countries, for a few years in advance, but that won't help me with dates in the past, and is really not a good solution, since the completeness of the solution is at best lacking.

I have searched a lot of places on the internet for a proper solution, and someone have made a solution for retrieving the timezones from the windows registry combined with some dll imports fromt he win32 API, but those are not perfect either.

So having almost tossed the towel into the ring, I stumpled upon another page on the internet http://www.codeplex.com/publicdomain/, and I thought, hmm, another crappy implementation, but no, its a full .NET implementation of the tz database http://www.twinsun.com/tz/tz-link.htm. I had looked at that timezone database myself a few times, but the sheer size and format of the database was just such a daunting task, that I have never fathomed to even be able to read that into a sensible .NET format.

The .NET library called PublicDomain is very easy to work with, much intuitive, and handles timezones and daylight savings very nice.

Its as simple as:

// Get the local computer's time zone
TzTimeZone dkZone = TzTimeZone.GetTimeZone("Europe/Copenhagen");

TzTimeZone ausZone = TzTimeZone.GetTimeZone("Australia/Adelaide");

DateTime dkNow = DateTime.UtcNow; //When in danish timezone

DateTime auzNow = ausZone.ToLocalTime(dkNow);
Gracefully right :)

Too bad Microsoft did not implement this.

The good part is that they will in .NET 3.5. I'm not sure of the extend of the implementation, or how well the daylight saving rules for each country is implemented, but at least its good that Microsoft at least have started looking in this direction.

multi-cast delegates and Predicate<T>

Since Predicate<T> that is used for finding stuff in a generics list is in fact a multi-cast delegate, I thought it might be possible to chain several Predicates to simplify multiple requirements for the elements returned.

Consider the following code:

Predicate<int> greaterThan5 = delegate(int x) { return x > 5; };
Predicate<int> lessThan10 = delegate(int x) { return x < 10; };

It would be cool if it would be possible to chain them, by doing a simple:

Predicate<int> combined = lessThan10 + greaterThan5;

And then:

List<int> resulting = allInts.FindAll(combined);

Unfortunately it dosen't work, or more precicely, it is only the last delegate that gets invoked.

It seems like MS did not envision people wanting to use multi-cast delegates for their predicates, and when looking at the List.FindAll implementation, its very clear, since it only invokes the delegate as it were a single cast one:

public List<T> FindAll(Predicate<T> match)
{
    if (match == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    List<T> list = new List<T>();
    for (int i = 0; i < this._size; i++)
    {
        if (match(this._items[i]))
        {
            list.Add(this._items[i]);
        }
    }
    return list;
}


So unfortunately you still need to do the old fashion way:

List<int> resulting = allInts.FindAll(lessThan10).FindAll(greaterThan5);

Lets hope they change it in c# 3.0

Delegates

Some years ago, when someone mentioned delegates I would shudder, and think back of all the times when I had tried to use them to something useful, and All I could think of at the time was to use them for events that other objects could subscribe to. This is also a nice feature, but when you think about it delegates is so much more.

I have started using delegates more heavily, and primarily to do Lazy Loading of data from a database. Lazy Loading is a technique where you only load the data when the application need it.  Lets say you have a class Customer, with a lot of properties, including an Orders collection. Instead of loading all orders and all other data that is related to the Customer, why not just load the data when the application makes a request for it, by invoking the get method of the Orders collection.

People would perhaps argue that it would require for the business objects to know the database structure, or if done a little more clever, need a reference to a Data Access Layer, but no, thats not neccesary, since you can use delegates for it.

consider the following delegate:

public delegate List<T> LoadDataDelegate<T>();


This delegate states that it will return a list of objects of type T.

okay then consider the following class

public class Customer
{

    /// <summary>
    /// Creates a new instance of the Customer class
    /// </summary>
    /// <param name="ordersDelegate"></param>
    public Customer(LoadDataDelegate<Order> ordersDelegate)
    {
        this.ordersDelegate = ordersDelegate;
    }

    private LoadDataDelegate<Order> ordersDelegate;

    private List<Order> orders;
    /// <summary>
    /// Gets a List of orders for the current Customer
    /// </summary>
    public List<Order> Orders
    {
        get
        {
            if (orders == null)
            {
                orders = ordersDelegate();
            }
            return orders;
            }
    }
   
    
}


And the following Mock data layer

public class DAL
{
    public List<Order> GetAllOrdersForCustomer(long customerID)
    {
        string sql = "select * from orders where customer_id=@customer_id";
        //etc
        //load into list
        }

        public Customer GetCustomer(long customerID)
        {
            Customer c = new Customer(delegate() { return GetAllOrdersForCustomer(customerID); });
            //load other data from the database

            return c;
        }
}


These two classes and the delegates, show a very simple way of using delegates for something intelligent and create an object that is capable of loading data from the database on demand, without knowing anything about Datalayers, SQL or anything else.

Nice right :)

Consider implementing all methods that can create, read, update and delete an object as delegates and all you would ever need to expose to your application is the business objects, and perhaps a few factory methods that could create new instances of objects with the delegates assigned to actual methods in your data layers :)

.NET culture names

I have searched the web a lot of times in need of a culture name for a specific language and culture, but I have never been able to find a complete list on the net.
I have compiled a list, and here it is for my own, and hopefully other people's use.

Language/countryCulture name
Afrikaans (South Africa) af-ZA
Albanian (Albania) sq-AL
Arabic (Algeria) ar-DZ
Arabic (Bahrain) ar-BH
Arabic (Egypt) ar-EG
Arabic (Iraq) ar-IQ
Arabic (Jordan) ar-JO
Arabic (Kuwait) ar-KW
Arabic (Lebanon) ar-LB
Arabic (Libya) ar-LY
Arabic (Morocco) ar-MA
Arabic (Oman) ar-OM
Arabic (Qatar) ar-QA
Arabic (Saudi Arabia) ar-SA
Arabic (Syria) ar-SY
Arabic (Tunisia) ar-TN
Arabic (U.A.E.) ar-AE
Arabic (Yemen) ar-YE
Armenian (Armenia) hy-AM
Azeri (Cyrillic, Azerbaijan) az-AZ-Cyrl
Azeri (Latin, Azerbaijan) az-AZ-Latn
Basque (Basque) eu-ES
Belarusian (Belarus) be-BY
Bosnian (Cyrillic, Bosnia and Herzegovina) bs-BA-Cyrl
Bosnian (Latin, Bosnia and Herzegovina) bs-BA-Latn
Bulgarian (Bulgaria) bg-BG
Catalan (Catalan) ca-ES
Chinese (Hong Kong S.A.R.) zh-HK
Chinese (Macao S.A.R.) zh-MO
Chinese (People's Republic of China) zh-CN
Chinese (Singapore) zh-SG
Chinese (Taiwan) zh-TW
Croatian (Bosnia and Herzegovina) hr-BA
Croatian (Croatia) hr-HR
Czech (Czech Republic) cs-CZ
Danish (Denmark) da-DK
Divehi (Maldives) div-MV
Dutch (Belgium) nl-BE
Dutch (Netherlands) nl-NL
English (Australia) en-AU
English (Belize) en-BZ
English (Canada) en-CA
English (Caribbean) en-CB
English (Ireland) en-IE
English (Jamaica) en-JM
English (New Zealand) en-NZ
English (Republic of the Philippines) en-PH
English (South Africa) en-ZA
English (Trinidad and Tobago) en-TT
English (United Kingdom) en-GB
English (United States) en-US
English (Zimbabwe) en-ZW
Estonian (Estonia) et-EE
Faroese (Faroe Islands) fo-FO
Filipino (Philippines) fil-PH
Finnish (Finland) fi-FI
French (Belgium) fr-BE
French (Canada) fr-CA
French (France) fr-FR
French (Luxembourg) fr-LU
French (Principality of Monaco) fr-MC
French (Switzerland) fr-CH
Frisian (Netherlands) fy-NL
Galician (Galician) gl-ES
Georgian (Georgia) ka-GE
German (Austria) de-AT
German (Germany) de-DE
German (Liechtenstein) de-LI
German (Luxembourg) de-LU
German (Switzerland) de-CH
Greek (Greece) el-GR
Gujarati (India) gu-IN
Hebrew (Israel) he-IL
Hindi (India) hi-IN
Hungarian (Hungary) hu-HU
Icelandic (Iceland) is-IS
Indonesian (Indonesia) id-ID
Inuktitut (Latin, Canada) iu-CA-Latn
Irish (Ireland) ga-IE
Italian (Italy) it-IT
Italian (Switzerland) it-CH
Japanese (Japan) ja-JP
Kannada (India) kn-IN
Kazakh (Kazakhstan) kk-KZ
Kiswahili (Kenya) sw-KE
Konkani (India) kok-IN
Korean (Korea) ko-KR
Kyrgyz (Kyrgyzstan) ky-KG
Latvian (Latvia) lv-LV
Lithuanian (Lithuania) lt-LT
Luxembourgish (Luxembourg) lb-LU
Macedonian (Former Yugoslav Republic of Macedonia) mk-M K
Malay (Brunei Darussalam) ms-BN
Malay (Malaysia) ms-MY
Maltese mt-MT
Maori mi-NZ
Mapudungun (Chile) arn-CL
Marathi (India) mr-IN
Mohawk (Mohawk) moh-CA
Mongolian (Cyrillic, Mongolia) mn-MN
Norwegian, Bokmål (Norway) nb-NO
Norwegian, Nynorsk (Norway) nn-NO
Persian (Iran) fa-IR
Polish (Poland) pl-PL
Portuguese (Brazil) pt-BR
Portuguese (Portugal) pt-PT
Punjabi (India) pa-IN
Quechua (Bolivia) quz-BO
Quechua (Ecuador) quz-EC
Quechua (Peru) quz-PE
Romanian (Romania) ro-RO
Romansh (Switzerland) rm-CH
Russian (Russia) ru-RU
Sami, Inari (Finland) smn-FI
Sami, Lule (Norway) smj-NO
Sami, Lule (Sweden) smj-SE
Sami, Northern (Finland) se-FI
Sami, Northern (Norway) se-NO
Sami, Northern (Sweden) se-SE
Sami, Skolt (Finland) sms-FI
Sami, Southern (Norway) sma-NO
Sami, Southern (Sweden) sma-SE
Sanskrit (India) sa-IN
Serbian (Cyrillic, Bosnia and Herzegovina) sr-BA-Cyrl
Serbian (Cyrillic, Serbia and Montenegro) sr-SP-Cyrl
Serbian (Latin, Bosnia and Herzegovina) sr-BA-Latn
Serbian (Latin, Serbia and Montenegro) sr-SP-Latn
Sesotho sa Leboa (South Africa) ns-ZA
Setswana (South Africa) tn-ZA
Slovak (Slovakia) sk-SK
Slovenian (Slovenia) sl-SI
Spanish (Argentina) es-AR
Spanish (Bolivia) es-BO
Spanish (Chile) es-CL
Spanish (Colombia) es-CO
Spanish (Costa Rica) es-CR
Spanish (Dominican Republic) es-DO
Spanish (Ecuador) es-EC
Spanish (El Salvador) es-SV
Spanish (Guatemala) es-GT
Spanish (Honduras) es-HN
Spanish (Mexico) es-MX
Spanish (Nicaragua) es-NI
Spanish (Panama) es-PA
Spanish (Paraguay) es-PY
Spanish (Peru) es-PE
Spanish (Puerto Rico) es-PR
Spanish (Spain) es-ES
Spanish (Uruguay) es-UY
Spanish (Venezuela) es-VE
Swedish (Finland) sv-FI
Swedish (Sweden) sv-SE
Syriac (Syria) syr-SY
Tamil (India) ta-IN
Tatar (Russia) tt-RU
Telugu (India) te-IN
Thai (Thailand) th-TH
Turkish (Turkey) tr-TR
Ukrainian (Ukraine) uk-UA
Urdu (Islamic Republic of Pakistan) ur-PK
Uzbek (Cyrillic, Uzbekistan) uz-UZ-Cyrl
Uzbek (Latin, Uzbekistan) uz-UZ-Latn
Vietnamese (Vietnam) vi-VN
Welsh cy-GB
Xhosa xh-ZA
Zulu zu-ZA

Enable MSDTC network access

I was developing a database layer using TransactionScope in .Net 2.0, and when opening the second connection I got the following error:

The partner transaction manager has disabled its support for remote/network transactions

This means that you need to enable network access on both the server/client that is running the application, but also on the database server(s) that you are connecting to. To do this you need to do:


First verify the "Distributed Transaction Coordinator" Service is
running on both database server computer and client computers
1.      Go to "Administrative Tools > Services"
2.      Turn on the "Distributed Transaction Coordinator" Service if it is not running

If it is running and client application is not on the same computer as
the database server, on the computer running database server
1.      Go to "Administrative Tools > Component Services"
2.      On the left navigation tree, go to "Component Services > Computers > My Computer"
3.      Right click on "My Computer", select "Properties"
4.      Select "MSDTC" tab
5.      Click "Security Configuration"
6.      Make sure you check "Network DTC Access", "Allow Remote Client", "Allow Inbound/Outbound", "Enable TIP"
7.      The service will restart
8.      You might have to restart the computer(s)

Enable CLR SQL Server 2005

I cant remember each time I have to turn this on how to do it, so here's a little blog for myself :)

Solution: Enable the server option 'clr enabled'


EXEC sp_configure 'show advanced options' , '1';
go
reconfigure;
go
EXEC sp_configure 'clr enabled' , '1'
go
reconfigure;
-- Turn advanced options back off
EXEC sp_configure 'show advanced options' , '0';
go

 

Way of the coder

No two programmers are created equal, and even though I like to think that I know best, and that the way that I do things are best, I seem to find that in styles of coding people are very different.

I like to create my code so I think its easy to read for others. E.g. whenever I create a method, if statement or other stuff that use curly braces {} I always place them on a seperate line as the only thing on that line. e.g

public bool DoUserExist(string userName)
{
   return false;
}

Other poeple insist on doing:
public bool DoUserExist(string userName){
   return false;
}

I find that annoying, I think the way that I do it makes it easier to see where a statement start and where it ends, when the curly braces are placed on the same like as the statement started, I think they can dissapear from the readers eye.
i.e.
if(true){
   return true;
}else{
   return false:
}

compared to:
if(true)
{
   return true;
}
else
{
   return false;
}

Admittedly the "wrong" coding style makes for more compressed code, but is that good?

Or how about

bool isReady=false;
if(isReady){
   //do the stuff
}

compared to:
bool isReady=false;

if(isReady==true)
{
   //do the stuff
}

i.e. should one write the implicit ==true or ==false in an if statement, I say yes because I think its easier to see what is intended instead of making thinks so compressed.
i.e.

if(!isReady && !canRun)
{
}

compared to:

if(isReady==false && canRun==false)
{
}

 

Just my 0.02$, but its a constant discussion where I'm working, but thats propably the case where ever java/c/c#/javascript programmers meet :p

.NET generics performance

You may wonder if the nice features of the generics List lacks in performance.

I wondered the same, so I decided to make a small and not very thorough test.

            ArrayList items = new ArrayList();
            for (int x = 0; x < 1000000;x++ )
            {
                items.Add("string" + x.ToString());
            }

            List<string> list = new List<string>();
            for (int x = 0; x < 1000000; x++)
            {
                list.Add("string" + x.ToString());
            }

            DateTime before = DateTime.Now;
            ArrayList wanted = new ArrayList();
            foreach (string str in items)
            {
                if (str.ToLower().EndsWith("0"))
                {
                    wanted.Add(str);
                }
            }
            DateTime after = DateTime.Now;
            Console.WriteLine("Time elapsed: {0} milliseconds", after.Subtract(before).TotalMilliseconds);

            before = DateTime.Now;
            List<string> wanteds = list.FindAll(delegate(string str) { return str.ToLower().EndsWith("0"); });
            after = DateTime.Now;
            Console.WriteLine("Time elapsed: {0} milliseconds", after.Subtract(before).TotalMilliseconds);
            Console.WriteLine("Press enter to continue");
            Console.ReadLine();

As you can see, I try to do the same things twice. The first time, I loop through an ArrayList with 1,000,000 string in it, to find those that ends in a 0. The strings that match are added to a new ArrayList.

The second time I do the same, just this time I am using the generics List, and the FindAll.

The performance difference are not great, but its there, and surprisingly it is in favour of the generics List.

On my computer, the first example gives the output:
Time elapsed: 890,625 milliseconds

and the second one:
Time elapsed: 765,625 milliseconds

which gives approximately 15% increase in performance, but that is only with one million items in the lists.

I summed it up in the following table, i could not move above 1 million items on my computer since I only have 2 GB of ram :)

And it seems like the 15% speed increase continues. 

Number if items ArrayList List<string>
1000 0 0
10000 15,625 0,000
100000 93,750 78,125
1000000 890,625 765,625

But what happens if the objects are a bit more complex than just strings?

            int count = 2000000;
            ArrayList items = new ArrayList(count);
            for (int x = 0; x < count; x++)
            {
                Servant s = new Servant();
                s.Name = "Jane"+x.ToString();
                s.Age = x % 2 == 0 ? 19:18;
                s.Sex = x % 2 == 0 ? SexFlag.Female : SexFlag.Male;
                items.Add(s);
            }

            List<Servant> list = new List<Servant>(count);
            for (int x = 0; x < count; x++)
            {
                Servant s = new Servant();
                s.Name = "Jane" + x.ToString();
                s.Age = x % 2 == 0 ? 19:18;
                s.Sex = x % 2 == 0 ? SexFlag.Female : SexFlag.Male;
                list.Add(s);
            }

            DateTime before = DateTime.Now;
            ArrayList wanted = new ArrayList();
            foreach (Servant s in items)
            {
                if (s.Sex == SexFlag.Female && s.Age > 18 && s.Age < 25 && s.Name.ToLower().EndsWith("0"))
                {
                    wanted.Add(s);
                }

            }
            DateTime after = DateTime.Now;
            
            
            Console.WriteLine("Time elapsed ArrayList: {0} milliseconds, found {1} items", after.Subtract(before).TotalMilliseconds,wanted.Count);

            before = DateTime.Now;
            List<Servant> wanteds = list.FindAll(delegate(Servant s) { return s.Sex == SexFlag.Female && s.Age > 18 && s.Age < 25 && s.Name.ToLower().EndsWith("0"); });
            after = DateTime.Now;
            Console.WriteLine("Time elapsed List<string>: {0} milliseconds, found {1} items", after.Subtract(before).TotalMilliseconds,wanteds.Count);

And the results:
 

Number if items ArrayList List<Servant>
1000 0,000 0,000
10000 0,000 0,000
100000 46,875 46,875
1000000 484,375 390,625
2000000 968,750 812,500

That is all nice, it seems like the generics have an advantage over the plain old way of doing things, but what about CPU usage? How does that sum up?

I ran the test with the more complex objects a few times, and monitored the CPU usage, my test results was simple, it seems like the dont differ much, but then again my testing tools is my eyes, so i can be greatly wrong :)

But considering my tests, it seems like a safe assumption to say that generics have no negative performance impact what so ever, it on the other hand gives a performance boost, when your lists are very large.

 

.NET generics

I recently started using generics for .NET 2.0 a while ago, and when faced with the problem of searching a custom list for a specific item, I found the following method: Find

public T Find (
    Predicate<T> match
)

The examples in the documentation are a bit lacking since they don't really show the power of what you can do with this method.

Excerpt from the documentation:


The Predicate is a delegate to a method that returns true if the object passed to it matches the conditions defined in the delegate. The elements of the current List are individually passed to the Predicate delegate, moving forward in the List, starting with the first element and ending with the last element. Processing is stopped when a match is found.


All this is fine, but the example that the documentation gives is vague:
using System;
using System.Collections.Generic;

public class Example
{
    public static void Main()
    {
        List<string> dinosaurs = new List<string>();

        dinosaurs.Add("Compsognathus");
        dinosaurs.Add("Amargasaurus");
        dinosaurs.Add("Oviraptor");
        dinosaurs.Add("Velociraptor");
        dinosaurs.Add("Deinonychus");
        dinosaurs.Add("Dilophosaurus");
        dinosaurs.Add("Gallimimus");
        dinosaurs.Add("Triceratops");

        Console.WriteLine();
        foreach (string dinosaur in dinosaurs)
        {
            Console.WriteLine(dinosaur);
        }

        Console.WriteLine("\nTrueForAll(EndsWithSaurus): {0}",
            dinosaurs.TrueForAll(EndsWithSaurus));

        Console.WriteLine("\nFind(EndsWithSaurus): {0}",
            dinosaurs.Find(EndsWithSaurus));

        Console.WriteLine("\nFindLast(EndsWithSaurus): {0}",
            dinosaurs.FindLast(EndsWithSaurus));

        Console.WriteLine("\nFindAll(EndsWithSaurus):");
        List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

        foreach (string dinosaur in sublist)
        {
            Console.WriteLine(dinosaur);
        }

        Console.WriteLine(
            "\n{0} elements removed by RemoveAll(EndsWithSaurus).",
            dinosaurs.RemoveAll(EndsWithSaurus));

        Console.WriteLine("\nList now contains:");
        foreach (string dinosaur in dinosaurs)
        {
            Console.WriteLine(dinosaur);
        }

        Console.WriteLine("\nExists(EndsWithSaurus): {0}",
            dinosaurs.Exists(EndsWithSaurus));
    }

    // Search predicate returns true if a string ends in "saurus".
    private static bool EndsWithSaurus(String s)
    {
        if ((s.Length > 5) &&
            (s.Substring(s.Length - 6).ToLower() == "saurus"))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

/* This code example produces the following output:

Compsognathus
Amargasaurus
Oviraptor
Velociraptor
Deinonychus
Dilophosaurus
Gallimimus
Triceratops

TrueForAll(EndsWithSaurus): False

Find(EndsWithSaurus): Amargasaurus

FindLast(EndsWithSaurus): Dilophosaurus

FindAll(EndsWithSaurus):
Amargasaurus
Dilophosaurus

2 elements removed by RemoveAll(EndsWithSaurus).

List now contains:
Compsognathus
Oviraptor
Velociraptor
Deinonychus
Gallimimus
Triceratops

Exists(EndsWithSaurus): False
*/

An example by me:

using System;
using System.Collections.Generic;
using System.Text;

namespace Generics_test
{
    class Class1
    {
    }

    public class Servant
    {
        string name = "";
        /// <summary>
        /// Gets/Sets the name of the servant
        /// </summary>
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        int age = 18;
        /// <summary>
        /// Gets/Sets the age of the servant
        /// </summary>
        public int Age
        {
            get
            {
                return age;
            }
            set
            {
                age = value;
            }
        }
        SexFlag sex = SexFlag.Male;
        /// <summary>
        /// Gets/Sets the sex of the servant
        /// </summary>
        public SexFlag Sex
        {
            get
            {
                return sex;
            }
            set
            {
                sex = value;
            }
        }
    }
    /// <summary>
    /// Enum for sex
    /// </summary>
    public enum SexFlag
    {
        Male,
        Female
    }

    public class Master
    {
        List<Servant> servants = new List<Servant>();
        public List<Servant> Servants
        {
            get
            {
                return servants;
            }
        }

    }
}

Okay, consider the fact that you want to find all Servants in an object of type Master with the following properties:

  • Age should be greater then 18, but less than 25
  • The servant should be female
  • your propably know where this is going :-D

One way of doing it in .NET 1.1 was to manually loop through all the Servant objects in the servants list of the Master object.
e.g.

        /// <summary>
        /// Finds all female servants of age between 18 and 25
        /// .NET 1.1 way of doing it.
        /// Lets pretend that the servants List is an ArrayList as well
        /// </summary>
        public ArrayList FindValidCandiates()
        {
            ArrayList valids = new ArrayList();
            foreach (Servant servant in servants)
            {
                if (servant.Sex == SexFlag.Female && servant.Age >= 18 && servant.Age < 26)
                {
                    //Servant is valid, add to valid arraylist
                    valids.Add(servant);
                }
            }
            return valids;
        }

.NET 2.0 and generics help you do this in a much easier way, and takes away the need of creating a specific method or specific code block just to select a few objects:

            List<Servant> valids= servants.FindAll(delegate(Servant servant) { return servant.Sex == SexFlag.Female && servant.Age >= 18 && servant.Age < 26; });

The nice feature here is something called anonymous delegates, and if you saw what i wrote in the start of the posting, Predicate is a delegate, and you can actually create it on the fly as you need it. Neat right :-D.

Another neat thing is if you need to find a specific item, you can do it by using the Find method:

            string wantedServantName = "Jane";
            Servant jane = servants.Find(delegate(Servant servant) { return servant.Name.ToLower() == wantedServantName.ToLower(); });

I must say that when I found these two features, and also the ForEach method, which makes the foreach loop on a List almost obsolete:

            servants.ForEach(delegate(Servant servant) { servant.Age += 1; });

So what are you waiting for, generics, .NET, now :-D