4

Can somebody explain what is the exact reason behind using Action<T> and Predicate<T> as delegates in C#

Douglas
  • 32,530
  • 8
  • 68
  • 88
Wondering
  • 4,622
  • 19
  • 69
  • 90

5 Answers5

11

Are you asking why they exist, or why they're defined as delegates?

As to why they exist, perhaps the best reason is convenience. If you want a delegate that returns no value and takes a single parameter of some type, they you could define it yourself:

public delegate void MyDelegate(int size);

And then later create one:

MyDelegate proc = new MyDelegate((s) => { // do stuff here });

And, of course, you'd have to do that for every different type you want to have such a method.

Or, you can just use Action<T>:

Action<int> proc = new Action<int>((s) => { /* do stuff here */ });

Of course, you can shorten that to:

Action<int> proc = (s) => { /* do stuff here */ });

As to "why are they delegates?" Because that's how function references are manipulated in .NET: we use delegates. Note the similarities in the examples above. That is, MyDelegate is conceptually the same thing as an Action<int>. They're not exactly the same thing, since they have different types, but you could easily replace every instance of that MyDelegate in a program with Action<int>, and the program would work.

Jim Mischel
  • 122,159
  • 16
  • 161
  • 305
4

What else would they be? Delegates are the most flexible and closest match to what Action<T>, Predicate<T> and Func<T> are modlling - an invocation list with specified parameter types (aka delegates).

Oded
  • 463,167
  • 92
  • 837
  • 979
3

The best way to explain why the idiom for performing action and predicate operations using the Action<T> and Predicate<T> delegates was chosen is to first consider the alternative. How could you accomplish the same thing without delegates? The next best thing would be to have interfaces IAction and IPredicate and force developers to declare a class and implement the appropriate interface for each different type of operation needed. But, the problem with that approach is that it requires more effort, more class proliferation, and less maintainable code. The delegate approach is a lot more convenient because you can write the logic inline with where it will be used using anonymous methods or lambda expressions.

Brian Gideon
  • 45,093
  • 12
  • 98
  • 145
  • The reason delegates are convenient is that compilers auto-generate a fair bit of code surrounding them. Conceptually, I don't see any reason why an interface `IAction` shouldn't be able to have an attribute such that when a compiler sees an attempt to assign a method group to an `IAction` it will check whether `IAction` contains an `Invoke` method with a signature that fits the message group and, if so, generate a class which implements `IAction.Invoke` as a call to the proper method. – supercat Dec 13 '12 at 18:33
  • @supercat: Yeah, I suppose it could. There is precedence for handling interfaces as first class citizens in C#...`IDisposable` for example. The `foreach` construct will call `Dispose` if the enumerator also implements `IDisposable`. The interaction of the `yield` keyword and `IEnumerator` is another example. I'm sure there's more. So yeah, what you are suggesting is almost certainly possible. – Brian Gideon Dec 14 '12 at 01:28
  • There are cases where interfaces would be more efficient than delegates, and cases where delegates are more efficient. Personally, I wish that every delegate had included and implemented an `IInvoke` interface (so for `Action` the interface would be `Action.IInvoke`); if normal practice was for code to use the interface type when practical, that would offer the best of both worlds. Incidentally, I find the inclusion of "BeginInvoke" in delegate types to be odd; I would think it more helpful to have included a `Bind` method which would... – supercat Dec 14 '12 at 15:38
  • ...turn a delegate with parameters, along with values for those parameters, into a `MethodInvoker`. For example, if `Act` is an `Action`, then `Act.Bind(5,"Hello")` would generate a `MethodInvoker` that would call `Act(5,"Hello")`. From what I understand, `BeginInvoke` has to bind a delegate and its parameters into a single object that's placed in the threadpool; rather than tying such parameter-binding functionality into the threadpool, it should be exposed separately. Among other things, it would allow things like `Control.BeginInvoke` to be type-safe. – supercat Dec 14 '12 at 15:48
2

Because they are delegates.

Henk Holterman
  • 236,989
  • 28
  • 287
  • 464
1

You are looking at the problem from the wrong point of view.

The question should not be "Why are Action<>, Func<> & Predicate<> delegates?" (The answer to that is "because they need to be")

The real question is, "Why do we have specific named objects, to handle simple delegate tasks? Why use Action<> in a place where a ordinary delegate would work?"

The answer is that those particular delegates are used a lot on the CLR itself, and since that they are used in CLR methods where the end developers will have to defined the method being called, the declaration for the delegate would have to be public. So, Microsoft could have defined thousands of delegates, each used by just one CLR method, or define a simple way to specific what type of delegate is needed.

James Curran
  • 95,648
  • 35
  • 171
  • 253