Func T with out parameter
ref
and out
are not part of the type parameter definition so you can't use the built-in Func
delegate to pass ref
and out
arguments. Of course, you can declare your own delegate if you want:
delegate V MyDelegate<T,U,V>(T input, out U output);
out parameter modifier in Func delegate (C#)
The Short Answer
You rarely need to worry about the in
and out
keywords in Generic type definitions. A class defined with in
/out
generic type parameters will usually "just work" when you're consuming it, and I'd wager that most devs will never write such a definition in their own code.
The Longer Answer
To get a complete explanation, you should read Covariance and Contravariance and Variance in Delegates. The rest of my answer is just some illustrative example code.
To simplify the explanation, I'm going explain in
and out
separately through Action<T>
and Func<TResult>
instead of Func<T,TResult>
.
The examples all use the following two classes:
class BaseClass {}
class DerivedClass : BaseClass {}
Covariance: out
For this example, I've mimicked Func<out TResult>
, but removed the out
(covariance) modifier to demonstrate its effect. Covariance allows us to use a func that returns DerivedType
anywhere that expects a func that returns BaseType
.
class CovarianceExamples
{
// This is similar to System.Func<out TResult>(), but with covariance removed
delegate TResult InvariantFunc<TResult>();
void InvariantFuncExample()
{
// Ignore the values of these variables; it's the types that are important
InvariantFunc<BaseClass> baseFunc = null;
InvariantFunc<DerivedClass> derivedFunc = null;
baseFunc = baseFunc; // Allowed
baseFunc = derivedFunc; // Not allowed; compile error!
}
void CovariantFuncExample()
{
// Ignore the values of these variables; it's the types that are important
Func<BaseClass> baseFunc = null;
Func<DerivedClass> derivedFunc = null;
baseFunc = baseFunc; // Allowed
baseFunc = derivedFunc; // Allowed
}
}
Contravariance: in
For this example, I've mimicked Action<in T>
, but removed the in
(contravariance) modifier to demonstrate its effect. Contravariance allows us to use an action that accepts BaseType
anywhere that expects an action that accepts DerivedType
.
class ContravarianceExamples
{
// This is similar to System.Action<in T>(T), but with contravariance removed
delegate void InvariantAction<T>();
void InvariantActionExample()
{
// Ignore the values of these variables; it's the types that are important
InvariantAction<BaseClass> baseAction = null;
InvariantAction<DerivedClass> derivedAction = null;
baseAction = baseAction; // Allowed
derivedAction = baseAction; // Not allowed; compile error!
}
void ContravariantActionExample()
{
// Ignore the values of these variables; it's the types that are important
Action<BaseClass> baseAction = null;
Action<DerivedClass> derivedAction = null;
baseAction = baseAction; // Allowed
derivedAction = baseAction; // Allowed
}
}
Using a out parameter in Func Delegate
You are just written answer.
If you in .net 4.0 or above you can specify variance for parameters.
public delegate TV MyFunc<in T, TU, out TV>(T input, out TU output);
Then use:
bool TryGetItem(string itemKey,out Item item);
MyFunc<string, Item, bool> func = TryGetItem;
Can I have an Action or Func with an out param?
Action and Func specifically do not take out or ref parameters. However, they are just delegates.
You can make a custom delegate type that does take an out parameter, and use it, though.
For example, the following works:
class Program
{
static void OutFunc(out int a, out int b) { a = b = 0; }
public delegate void OutAction<T1,T2>(out T1 a, out T2 b);
static void Main(string[] args)
{
OutAction<int, int> action = OutFunc;
int a = 3, b = 5;
Console.WriteLine("{0}/{1}",a,b);
action(out a, out b);
Console.WriteLine("{0}/{1}", a, b);
Console.ReadKey();
}
}
This prints out:
3/5
0/0
Implement calling delegate with out parameters
Just use the same scheme as in your example of SafetyExecuteFunction<T>(Func<T> func)
.
One thing you have to pay attention to is that you need to use a temporary local variable for the out parameter.
private TResult SafetyExecuteFunctionWithOut<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
TResult result = default(TResult);
T2 arg2Result = default(T2); // Need to use a temporary local variable here
SafetyExecuteMethod(() => result = func(arg1, out arg2Result));
arg2 = arg2Result; // And then assign it to the actual parameter after calling the delegate.
return result;
}
Calling the function does then work like this:
public bool CanUpdateUser(string userName, out string errorMessage)
{
bool result = SafetyExecuteFunctionWithOut<string, string, bool>(_innerSession.CanUpdateUser, userName, out errorMessage);
return result;
}
Note, that you have to pass _innerSession.CanUpdateUser
as a parameter to SafetyExecuteFunctionWithOut
instead of using a lambda expression.
Using the naive attempt:
private TResult SafetyExecuteFunctionWithOut<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
TResult result = default(TResult);
SafetyExecuteMethod(() => result = func(arg1, out arg2));
return result;
}
creates the error message:
CS1628 Cannot use ref or out parameter 'arg2' inside an anonymous
method, lambda expression, or query expression
Why you are not allowed to do that is explained in this answer.
Using Func T delegate in C#
In both cases, the lambda expressions that you have written:
()=>GreatherThan(1,2)
()=> calculateTwo(2)
represent functions with no parameters, as indicated by the empty brackets ()
. It does not matter what you do inside the lambda expression. () => calculateTwo(2)
represents a function with no parameters, that calls calculateTwo(2)
as the only thing it does. Imagine these:
int AnonymousFunction1() {
return calculateTwo(2);
}
bool AnonymousFunction2() {
return GreaterThan(1, 2);
}
Think of as these as what you are actually passing to Task.Run
by writing those lambda expressions. These functions are clearly compatible with Func<int>
and Func<bool>
, and not compatible with Func<int, int, bool>
.
How to declare a generic delegate with an out parameter
Actually, Func is just a simple delegate declared in the .NET Framework. Actually, there are several Func delegates declared there:
delegate TResult Func<TResult>()
delegate TResult Func<T, TResult>(T obj)
delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, T3, TResult>(T1 obj1, T2 obj2, T3 obj3)
delegate TResult Func<T1, T2, T3, T4, TResult>(T1 obj1, T2 obj2, T3 obj3, T4 obj4)
delegate TResult Func<T1, T2, ... , T16, TResult>(T1 obj1, T2 obj2, ..., T16 obj16)
So the only thing you can do is declare your custom delegate:
delegate bool MyFunc<T1, T2>(T1 a, out T2 b)
Related Topics
Algorithm for Simplifying Decimal to Fractions
Nullable Type Issue with : Conditional Operator
Format of the Initialization String Does Not Conform to Specification Starting at Index 0
Getting Path Relative to the Current Working Directory
How to Programmatically Fill in a Form and 'Post' a Web Page
Tuples( or Arrays ) as Dictionary Keys in C#
Making Entity Class Closed for Changes
Invalid Length for a Base-64 Char Array
Insert Entire Datatable into Database at Once Instead of Row by Row
C# Dictionary - One Key, Many Values
C# Error: Parent Does Not Contain a Constructor That Takes 0 Arguments
Check for Device Change (Add/Remove) Events
"On Exit" for a Console Application
C# Webbrowser Control - Form Submit Not Working Using Invokemember("Click")