Using Predicates with Generic List Methods

Illustrates the use of a Predicate to enable the Generic List FindAll method to create a sub List<> of wildcard filters.

The Generic List class is a lot more useful than its pre- .NET 2.0 brethren such as the Hashtable.  The List class offers a number of "Find" type builtin methods.

In order to enable a specific Find for the FindAll method, we pass in a Predicate that acts as a way for the List class to filter based on a boolean result for each comparison of items in its list, and it returns a new List<T> containing all the matches.

Here is some sample code that enables filtering on an asterisk that represents a wildcard character for a list of phone numbers that are supposed to be "blocked" from being called:

 

public static List<String> BlockedNumbers = new List<String>();

        // this method just uses the SqlHelper v2 to fill the List
        private static void PopulateBlockedNumbers()
        {
            DataSet ds = SqlHelper.ExecuteDataset(connectionString, "dbo.Get_BlockedNumbers", null);
            DataTable dt = ds.Tables[0];
            foreach(DataRow row in dt.Rows)
                BlockedNumbers.Add((string)row["PhoneNumber"]);    
        }

        // This method is used to clear and repopulate List when someone 
    // adds or deletes a number in the DB
     public static void RefreshBlockedNumbers()
        {
            BlockedNumbers.Clear();
            PopulateBlockedNumbers();
        }

          // this is the predicate used by the FindAll method
      private static bool EndsWith(string s)
        {
            if(s.IndexOf("*")>-1)
                return true;
            else
                return false;
        }

        //this method checks if list contains a phone number,
    // then it gets a sublist of all phonenumbers with a wildcard "*"
    // and checks those too. The wildcard allows you to specify "987123*"
    // so that any number starting with 987123 would be blocked,
    // regardless of the last 4 digits.
        public static bool IsNumberBlocked(string phoneNumber)
        {
            bool retval = false;
            if(BlockedNumbers.Contains(phoneNumber))
                retval=true;            
                   List<String> sublist= BlockedNumbers.FindAll(EndsWith);
                   string s2 = "";
                   foreach (string s in sublist)
                   {
                       s2 = s.Substring(0, s.IndexOf("*"));
                       if (phoneNumber.StartsWith(s2))
                       {
                           retval = true;
                           break;
                       }
                   }         

            return retval;
        }
Note that when passing the Predicate method to the FindAll method of the List object, you pass only the name with no parameter, as it represents a surrogate for the contained type (in this case, String). The List class then calls the Predicate for every item and uses the bool result of the call to determine whether it should be included in the sublist result that it returns.

I hope the above sample illustrates the technique.
By Peter Bromberg   Popularity  (13838 Views)