Click here to Skip to main content
Click here to Skip to main content
Go to top

Passing parameters to predicates

, 1 Aug 2006
Rate this:
Please Sign up or sign in to vote.
Simple and thread-safe way to reuse predicates

Introduction

Inability to pass parameters to predicates often made me consider writing search functions for custom collections. One day I figured enough is enough. In this example I will demonstrate the workaround to passing parameters to predicates, and reasoning involved. There is no download - the code is tiny. I will use MSDN’s example code for List.TrueForAll as the starting point.

Intermediate step

What if we wanted to reuse the predicate to search not only for dinosaur names that end on “saurus”, but also for those that end on “tor”? Shouldn’t it be easily done?

I only kept the minimum required code from MSDN example. To approximate a more common situation, the code is moved into a class DinoClassification, which hypothetically classifies dinosaurs. The predicate and the variable that it uses are made non-static and also moved into that class.
using System;
using System.Collections.Generic;


public class DinoClassification
{
    private string m_Suffix;

    public void Classify()
    {
        List<string> dinosaurs = new List<string>(new string[] {
            "Compsognathus", "Amargasaurus", "Oviraptor", "Velociraptor",
            "Deinonychus", "Dilophosaurus", "Gallimimus", "Triceratops"});

        m_Suffix = "saurus";
        Console.WriteLine("\nFind(EndsWith {0}): {1}", m_Suffix, 
            dinosaurs.Find(EndsWith));
        m_Suffix = "tor";
        Console.WriteLine("\nFind(EndsWith {0}): {1}", m_Suffix, 
            dinosaurs.Find(EndsWith));
    }

    // Search predicate returns true if a string ends in correct suffix.
    private bool EndsWith(String s)
    {
        if ((s.Length >= m_Suffix.Length) &&
            (s.Substring(s.Length - m_Suffix.Length).ToLower() == 
                    m_Suffix.ToLower()))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

public class Example
{
    public static void Main()
    {
        DinoClassification dcl = new DinoClassification();
        dcl.Classify();
    }
}

This works in a single-threaded environment. In multi-threaded application we could have m_Suffix written to from different threads, which would cause havoc. To make this code thread-safe one would need to have the search inside a critical section. This is out of question. Having iteration over a collection of arbitrary size in a critical section is not an option.

There’s another fact that I personally dislike about this implementation. DinoClassification is a dinosaur classification class. It has nothing to do with matching strings that make up a dinosaur name. Member variable m_Suffix and predicate EndsWith do not belong in DinoClassification class.

So, what I really want is:

  • Maintain class' thread safety with no effort on my part.
  • Move the predicate out of my class.
  • Keep it all as simple as possible.

Solution

Why not do just that? Wrap a variable and a predicate together and tuck away into a separate class.
using System;
using System.Collections.Generic;


public class EndsWith
{
    private string m_Suffix;

    // Initializes with suffix we want to match.
    public EndsWith(string Suffix)
    {
        m_Suffix = Suffix;
    }

    // Sets a different suffix to match.
    public string Suffix
    {
        get { return m_Suffix; }
        set { m_Suffix = value; }
    }
    
    // Gets the predicate.  Now it's possible to re-use this predicate with 
    // various suffixes.
    public Predicate<string> Match
    {
        get { return IsMatch; }
    }

    private bool IsMatch(string s)
    {
        if ((s.Length >= m_Suffix.Length) &&
            (s.Substring(s.Length - m_Suffix.Length).ToLower()
                                                 == m_Suffix.ToLower()))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}


public class DinoClassification
{
    public void Classify()
    {
        List<string> dinosaurs = new List<string>(new string[] {
            "Compsognathus", "Amargasaurus", "Oviraptor", "Velociraptor",
            "Deinonychus", "Dilophosaurus", "Gallimimus", "Triceratops"});

        Console.WriteLine("\nFind(EndsWith): {0}", 
            dinosaurs.Find(new EndsWith("saurus").Match));
        EndsWith predicate = new EndsWith("tor");
        Console.WriteLine("\nFind(EndsWith): {0}", 
            dinosaurs.Find(predicate.Match));
        predicate.Suffix = "hus";
        Console.WriteLine("\nFind(EndsWith): {0}", 
            dinosaurs.Find(predicate.Match));
    }
}



public class Example
{
    public static void Main()
    {
        DinoClassification dcl = new DinoClassification();
        dcl.Classify();
    }
}

EndsWith is a class that wraps the predicate and the variable. The variable can be set either through constructor parameter or Suffix property. Class has two properties. Property Suffix allows setting a new value for predicate to match. The Match property is of type predicate<string>. It returns the “parameterized” predicate used in Find(), Exists(), etc.

What was achieved in this example:

  • DinoClassification is thread-safe as long as there is no member variable of type EndsWith.
  • DinoClassification is not cluttered with code pieces that belong to utility layer.
  • Predicate parameters are passed to constructor and may later be modified through properties of the wrapper class.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Alex Perepletov
Software Developer (Senior)
Canada Canada
No Biography provided

Comments and Discussions

 
GeneralMy vote of 4 PinmemberRicky Owen31-Jan-11 0:21 
GeneralVery neat PinmemberPeter Karaulshchykov9-Feb-10 5:40 
GeneralNice Pinmembermikeperetz14-Mar-09 9:01 
GeneralSimplier than this PinmemberNormand1-Aug-08 5:34 
GeneralRe: Simplier than this Pinmemberopenshac21-Dec-09 4:38 
GeneralDoh PinmemberWesFromKC8-Aug-06 12:01 
JokeRe: Doh PinmemberAndreas Saurwein Franci Gonalves29-May-08 7:46 
GeneralSuggestions PinmemberSteve Hansen31-Jul-06 22:42 
GeneralRe: Suggestions PinmemberAlex Perepletov2-Aug-06 15:56 
GeneralRe: Suggestions PinmemberSteve Hansen2-Aug-06 19:52 
GeneralRe: Suggestions Pinmembershivashankarp24-Dec-06 19:33 
GeneralRe: Suggestions PinmemberRichard Deeming10-Aug-06 8:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 1 Aug 2006
Article Copyright 2006 by Alex Perepletov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid