相关文章推荐
千杯不醉的甘蔗  ·  UCOSiii interrupt problem·  1 月前    · 
另类的牛肉面  ·  国际组织类型·  1 月前    · 
茫然的茶叶  ·  桌面级3D打印机原理- ...·  2 月前    · 
寂寞的红薯  ·  莆田学院附属医院·  1 年前    · 
Skip to content

Delegate types in C#: Action vs Func vs Predicate

Published on in C#

Last updated on

Action doesn't return anything, Func does. Predicate takes one parameter and returns a boolean.

Table of contents

Action<T1, T2, T3, ...>

  • Action has no return value.
  • The types T1 , T2 , T3 and so on specify the parameters' types.
  • There can be between 0 and 16 parameters:
  • Action
  • Action<T1>
  • Action<T1, T2>
  • Action<T1, T2, T3>
  • Action<T1, T2, T3, ..., T16>
  • Examples:

  • Action takes no parameters and returns nothing.
  • Action<int> takes one int parameter and returns nothing.
  • Action<int, bool, int> takes three parameters of types int , bool and int , in that order, and returns nothing.
  • Action lambda1 = () =>
        Console.WriteLine("lambda1 was called");
        // No return value
    Action<int> lambda2 = (int param1) =>
        Console.WriteLine($"lambda2 was called with {param1}");
        // No return value
    Action<int, bool, int> lambda3 = (int param1, bool param2, int param3) =>
        Console.WriteLine($"lambda3 was called with {param1}, {param2} and {param3}");
        // No return value
    

    Func<T1, T2, T3, ..., TResult>

  • Func returns a value of type TResult.
  • The types T1, T2, T3 and so on specify the parameters' types.
  • There can be between 0 and 16 parameters:
  • Func<TResult>
  • Func<T1, TResult>
  • Func<T1, T2, TResult>
  • Func<T1, T2, T3, TResult>
  • Func<T1, T2, T3, ..., T16, TResult>
  • TResult is always in the last position, i.e. the last type always specifies the return value's type.
  • Examples:

  • Func<string> takes no parameters and returns a string.
  • Func<int, string> takes one int parameter and returns a string.
  • Func<int, bool, int, string> takes three parameters of types int, bool and int, in that order, and returns a string.
  • Func<string> lambda1 = () =>
        return "lambda1 was called";
    Func<int, string> lambda2 = (int param1) =>
        return $"lambda2 was called with {param1}";
    Func<int, bool, int, string> lambda3 = (int param1, bool param2, int param3) =>
        // `null` return value is ok too
        // because strings can be null
        if (!param2) return null;
        return $"lambda3 was called with {param1}, {param2} and {param3}";
    

    Predicate<T>

  • Predicate returns a boolean.
  • Predicate takes one parameter of type T.
  • Examples:

  • Predicate<int> takes one int parameter and returns a boolean.
  • Predicate<string> takes one string parameter and returns a boolean.
  • Predicate<int> IsPositive = (int param) =>
        return param > 0;
    Predicate<string> StartsWithFoo = (string param) =>
        return param?.StartsWith("foo") ?? false;
    

    Predicate<T> vs Func<T, bool>

    Predicate<T> is effectively the same as Func<T, bool>. They both take a single parameter of type T and return a boolean.

    That said, they are not assignment-compatible. Example from the linked Stack Overflow answer by Daniel Earwicker (slightly modified):

    public static bool IsNegative(int x)
        return x < 0;
    static void Main(string[] args)
        Predicate<int> p = IsNegative;
        Func<int, bool> f = IsNegative;
        p = f; // Doesn't work
        f = p; // Doesn't work
    

    Which one to use, Predicate<T> or Func<T, bool>?

    If you can choose, my hunch is that Func is better because:

  • Func has overloads that take more than one input type, so it's more flexible than Predicate.
  • Func<T, bool> is clear (given that you know how Funcs work), whereas Predicate is more niche and makes sense only if you know what a "predicate" is.
  • On the other hand, Predicate<T> is short and descriptive, so I don't have a strong opinion which one to prefer.

    Further resources

    This blog post was inspired by Scott Steffes's YouTube video Generic Delegate Types (Action, Func, Predicate), in C#. There's interesting discussion about the delegate keyword versus lambda syntax in a Reddit thread around the video.

    See also these pages in the .NET docs: