Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Why LINQ requires you to Func?

, 29 Aug 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
What exactly is Func? What has it got to do with LINQ?

Introduction

When LINQ appeared on our screens, it brought along a requirement under the guise of 'Func' whenever you wanted to do anything substantial, such as supply the contents of a where clause:

What exactly is Func? What are we actually being asked for here? This is a journey that begins with delegates.

First, let's consider how we create an object:

class Program
    {
        //Define a class, including what parameters it needs
        class Car
        {
            public Car(string make)
            {
                Console.WriteLine("{0} created", make);
            }
        }
 
        static void Main(string[] args)
        {
            //Create a variable capable of holding type 'Car'
            Car pointerToObject;
 
            //Set that reference to an instance
            pointerToObject = new Car("Ford Fiesta");
            
            Console.ReadLine();
        }

As you can see, this takes three steps:

  • We define a class (Car)
  • We create a variable of that type
  • Then we create an instance of the class and set the variable to a reference of it

A bit simple? Stick with me...

Now let's see how we do this with delegates. I invite you to spot the difference:

class Program
    {
        //Define a delegate, including what parameters it needs
        delegate void Car(string make);
 
        //Create a method with the same parameters
        private static void ReturnCarName(string make)
        {
            Console.WriteLine("{0} created", make);
        }
 
        static void Main(string[] args)
        {
            //Create a variable that is capable of holding delegate type 'Car' 
            Car pointerToMethod;
            
            //Set it to the method
            pointerToMethod = ReturnCarName;
 
            //Call it
            pointerToMethod("Ford Fiesta");
 
            Console.ReadLine();
        }
    }

In both instances, Car acted as a pointer to some functionality, the first was a reference to an instance of a class whereas the second was reference to a method. You've spotted the difference.

  • Class type = Reference to a object
  • Delegate type = Reference to a method

Directly from the C# Spec:

1.11 Delegates

A delegate type represents references to methods with a particular parameter list and return type. Delegates make it possible to treat methods as entities that can be assigned to variables and passed as parameters.

That last sentence is extremely important. Delegates allow us to pass references to methods in the same way we can pass references to objects.

This is the purpose of Func. Instead of being forced to define our own delegate (what we did in the second example, named Car), we're provided with a definition of a delegate of which we have to provide a suitable reference.

Let me hammer this home:

Usually, we call methods which a reference (or value of) an object, instead the Where method is requesting a reference to a method which is the same type of Func.

Let's see a concrete example:

Scenario: Select all names beginning with M

To do this, I need to create a method that tests a given item, and return true if it begins with M:

class LinqWhereClause
    {
        public void WhereClause()
        {
            var names = new List<string>();
            names.Add("Steve");
            names.Add("Dave");
            names.Add("Matt");
 
            //Passing in the method in the constructor for Func<string, bool>
            Func<string, bool> myFunc = new Func<string, bool>(MyWhereClause); 
 
            var thing = names.Where(myFunc); //Returns Matt
         }
 
        public bool MyWhereClause(string item)
        {
            return item.StartsWith("M");
        }
    }

However, because of these features introduced in (introduced in C# 2*):

  • Removing the awkward delegate syntax
  • Anonymous methods, allowing you to define a delegate instance's action in-line

We can supply it in a way I suspect you're familiar with:

class LinqWhereClause
    {
        public void WhereClause()
        {
            var names = new List<string>();
            names.Add("Steve");
            names.Add("Dave");
            names.Add("Matt");
 
            //The method is being passed 'inline', can you see how this is the same as above?
            Func<string, bool> myFunc = new Func<string, bool>(item => item.StartsWith("M"));
 
            var thing = names.Where(myFunc); //Returns Matt
        }
    }

* Surprising isn't it, this has been available since 2005!

Hopefully, you can see that the only difference is that we've compressed the method definition, moving towards a more fluid, expressive form of programming. Which, in conjunction with anonymous methods is the only purpose of Func.

There are 17 varieties of Func, each one specifying a different number of parameters to enable you to pick the right one for your task. There is also a sibling Action which has the same purpose expected for not returning a value.

So... why not have a glance over your codebase? How many times have you used Func without giving it a second thought? Even better, how could you produce your own methods that accept functionality as a parameter in the form of Func?

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Matthew Edmondson
Software Developer
United Kingdom United Kingdom
Selected articles are published on codeproject. For all of my content, including how to contact me please visit my blog.
Follow on   Twitter   LinkedIn

Comments and Discussions

 
Generalvery helpful PinmemberKMHickey4-Sep-14 6:15 
GeneralMy vote of 1 [modified] Pinmemberscorpyj2-Sep-14 5:00 
GeneralRe: My vote of 1 PinmemberMatthew Edmondson2-Sep-14 6:16 
QuestionSomething wrong with example code PinmemberKMHickey1-Sep-14 15:07 
AnswerRe: Something wrong with example code PinmemberMatthew Edmondson2-Sep-14 5:53 

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 | Terms of Use | Mobile
Web04 | 2.8.150414.1 | Last Updated 29 Aug 2014
Article Copyright 2014 by Matthew Edmondson
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid