A typical syntax for Func
is:
Func<T, TResult>
Referring MSDN: http://msdn.microsoft.com/en-us/library/bb549151%28v=vs.110%29.aspx
Func
is a part of System
namespace and is defined as:
public delegate TResult Func<in T, out TResult>(T arg)
Where:
in T
: Type of the parameter of the method to encapsulate
out TResult
: Type of the return value of the method
Let's think about some scenarios where someone wants to:
- Format a number
- Make text to upper case
Now-a-days, we have many options to do, we can choose in-built methods/functions or we can define own methods/functions, especially when we are delivering some kind of finished product to external users. These type of users would not be aware and do not want to know the internal functionality but they want accurate results.
So, let's define our own methods in a simpler way:
- Define an Interface:
IWithoutFuncType
namespace MyStuff
{
public interface IWithoutFuncType
{
string ToUpper(string textToUpper);
string FormatMe(int num);
string ToSum(int num1, int num2);
}
}
- Implement interface:
IWithoutFuncType
to class WithoutFuncType
using System;
using System.Globalization;
namespace MyStuff
{
public class WithoutFuncType : IWithoutFuncType
{
public string ToUpper(string textToUpper)
{
return textToUpper.ToUpper(CultureInfo.InvariantCulture);
}
public string FormatMe(int num)
{
return String.Format("You entered {0}.", num);
}
public string ToSum(int num1, int num2)
{
return string.Format("Sum of {0} and {1} = {2}", num1, num2, num1 + num2);
}
}
}
- Compile the above class and run in console:
using System;
using System.Collections.Generic;
namespace MyStuff
{
class Program
{
static void Main(string[] args)
{
IWithoutFuncType withoutFuncType = new WithoutFuncType();
Console.WriteLine(withoutFuncType.ToUpper("this is without func type"));
Console.WriteLine();
Console.WriteLine(withoutFuncType.FormatMe(109));
Console.WriteLine(withoutFuncType.ToSum(101, 9));
Console.ReadLine();
}
}
}
The output of the above is very obvious, you will get things as defined. From here, our need to Func
exists. Above is a very simple example, there might be situations where we need to handle typical complex data and conditions for that do you want to write hundreds of a line to just getting a sum of two numbers or make it as UpperCase
? Frankly, I hate to write a method which would have more than- lines …
We can define the following Func
types for our basic operations, look at the following snippet:
Func<string, string> _toUpper = st => st.ToUpper(CultureInfo.InvariantCulture);
Func<int, string> _formatMe = n => string.Format("You entered {0}", n);
Func<int, int, string> _toSum = (n, m) => string.Format("Sum of {0} and {1} = {2}", n, m, n + m);
Isn’t it so simple, looks like one-liner and these methods defined themselves by their names. Let's take first _toUpper Func
, it is accepting string
as parameter and returning string
as a result and name is toUpper
which tells, supply me, any string
and I will return string
in UpperCase
.
Also, it is very easy to use the above Func
. You just need to call its Invoke()
method with desired parameters to fire/trigger. See the below snippet:
Console.WriteLine(_toUpper.Invoke(109));
Pretty easy, isn’t it
Let's think more complex areas you want performance and need to write a clean code. Due to the scope of this article, I am not going to define more live examples, you can think-over, here is a complete snippet defining Func
with best typical usages:
- Define an interface
IWithFuncType
using System.Collections.Generic;
namespace MyStuff
{
public interface IWithFuncType
{
string FormatNumberAndMakeToUpper(int num);
string GiveMeSumInDefinedFormat(int num1, int num2);
string MakeMeInUpperCase(string stringToUpper);
List<string> GiveMeFullNames(IEnumerable<FullName> suppliedNames);
}
}
- Implement interface
IWithFuncType
with class WithFuncType
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
namespace MyStuff
{
public class WithFuncType : IWithFuncType
{
readonly Func<string, string> _toUpper = st => st.ToUpper(CultureInfo.InvariantCulture);
readonly Func<int, string> _formatMe = n => string.Format("You entered {0}", n);
readonly Func<int, int, string> _toSum =
(n, m) => string.Format("Sum of {0} and {1} = {2}", n, m, n + m);
public string FormatNumberAndMakeToUpper(int num)
{
return MakeMeInUpperCase(_formatMe.Invoke(num));
}
public string GiveMeSumInDefinedFormat(int num1, int num2)
{
return _toSum.Invoke(num1, num2);
}
public string MakeMeInUpperCase(string stringToUpper)
{
return _toUpper.Invoke(stringToUpper);
}
public List<string> GiveMeFullNames(IEnumerable<FullName> suppliedNames)
{
var fullNames = new List<string>();
fullNames.AddRange(suppliedNames.Select(fullName => fullName.ToString(NameFormatter)));
return fullNames;
}
private string NameFormatter(FullName stringToFormat)
{
var builder = new StringBuilder();
builder.AppendFormat("{0} {1} {2}", stringToFormat.FirstName,
stringToFormat.IsMiddleNameSupplied ?
stringToFormat.MiddleName : "-", stringToFormat.LastName);
return builder.ToString();
}
}
public class FullName
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public bool IsMiddleNameSupplied
{
get { return !string.IsNullOrEmpty(MiddleName); }
}
public string ToString(Func<FullName, string> formatter)
{
return formatter(this);
}
}
}
- Compile and run into Console:
using System;
using System.Collections.Generic;
namespace MyStuff
{
class Program
{
static void Main(string[] args)
{
IWithFuncType withFuncType = new WithFuncType();
Console.WriteLine(withFuncType.MakeMeInUpperCase("this is with func type"));
Console.WriteLine();
Console.WriteLine(withFuncType.FormatNumberAndMakeToUpper(109));
Console.WriteLine(withFuncType.GiveMeSumInDefinedFormat(101, 9));
var fullName = GetSomeFullNames();
var names = withFuncType.GiveMeFullNames(fullName);
Console.WriteLine();
Console.WriteLine("A typical use of Func Type");
Console.WriteLine();
foreach (var name in names)
{
Console.WriteLine("Full Name: {0}", name);
}
Console.ReadLine();
}
private static void StuffWithFuncType()
{
IWithFuncType withFuncType = new WithFuncType();
Console.WriteLine(withFuncType.MakeMeInUpperCase("this is with func type"));
Console.WriteLine();
Console.WriteLine(withFuncType.FormatNumberAndMakeToUpper(109));
Console.WriteLine(withFuncType.GiveMeSumInDefinedFormat(101, 9));
var fullName = GetSomeFullNames();
var names = withFuncType.GiveMeFullNames(fullName);
Console.WriteLine();
Console.WriteLine("A typical use of Func Type");
Console.WriteLine();
foreach (var name in names)
{
Console.WriteLine("Full Name: {0}", name);
}
}
private static List<FullName> GetSomeFullNames()
{
return new List<FullName>
{
new FullName
{
FirstName = "Gaurav",
MiddleName = "Kumar",
LastName = "Arora"
},
new FullName
{
FirstName = "Joseph",
MiddleName = "",
LastName = "Bulger"
},
new FullName
{
FirstName = "Shuby",
MiddleName = "",
LastName = "Arora"
}
};
}
}
}
In the above, user just needs to provide a list of FullName
and our program will return the complete name with pre-defined format or business logic.
What To Do Next?
- You can download the complete example of
FuncType
from GitHub: https://github.com/garora/somestuff
- Refer to MSDN for more information: http://msdn.microsoft.com/en-us/library/bb549151%28v=vs.110%29.aspx
Note: If you find any issue with the above article, please feel free to write your comments, also you can correct the same from GitHub project.