There is a generic function with a return type.
TResult Invoke<TResult>(Func<string, TResult> callback)
{
string message = Generate_some_string();
return callback(message);
}
And also there is a similar one without a return type since there is no Func.
void Invoke(Action<string> callback)
{
string message = Generate_some_string();
callback(message);
}
But these are duplicate code. Once Invoke changes, Invoke has to be changed correspondingly. Is there any way to eliminate the duplicate code?
Thanks,
Jim
You could try something like this:
void Invoke(Action<string> callback)
{
Invoke<int>(s=>{callback(s);return 0;});
}
That way all your logic stays in the Func version and your Action version should never have to change.
Another option would be to create a ToFunc conversion routine, and place the onus on your callers to change their action into a func:
public static Func<TIn, TResult> ToFunc<TIn, TResult>(this Action<TIn> a)
{
return input =>
{
a(input);
return default(TResult);
};
}
Related
I am new to Func/Action/Predicate and want to know what is the best way to refactor my code as I will potentially have a lot of repeated code.
I have created 2 extension methods which take a Func parameter (always returning bool):
public static void MyExtension<T>(this T obj, Func<T, bool> predicate)
{
do
{
//function code
} while (predicate(obj));
}
public static void MyExtension<T1, T2>(this T1 obj, T2 OtherObject, Func<T1, T2, bool> predicate)
{
do
{
//function code
} while (predicate(obj, OtherObject));
}
What I want, is to only code the do/while loop once as I might have a lot of functions which will only generate a different Func but will all want to run the same do/while loop.
I was thinking something like this, which takes any Func parameter and runs it on each loop. The code in the loop doesn't care about the types passed into the Func.
public static void DoLoop(Func predicate)
{
do
{
//function code
} while (predicate);
}
But this clearly doesnt work. Does anyone know how to resolve this, or am I doing something fundamentally wrong?
The end result is I want to call the code like below:
var Obj = new MyObj();
Obj.MyExtension((x) => x.Prop1.Contains("string"));
var OtherObj = new MyObj();
Obj.MyExtension(OtherObj, (x,y) => x.Prop1.Contains("string") && y.Prop1.Contains("other"));
Thanks.
Since your generic methods are parameterized on a different number of generic types, you need to keep all function signatures in place in order for the calling code to compile. However, you can move the implementation into a common helper method to reduce repeated code:
// This is your single implementation
private static void DoLoop(Func<bool> predicate) {
do {
//function code
} while (predicate());
}
// These are the wrappers
public static void MyExtension<T>(this T obj, Func<T, bool> predicate) {
DoLoop(() => predicate(obj));
}
public static void MyExtension<T1, T2>(this T1 obj, T2 OtherObject, Func<T1, T2, bool> predicate) {
DoLoop(() => predicate(obj, OtherObject));
}
Wrappers construct parameter-less predicate, and pass it to the private DoLoop method, which provides the implementation.
Is there a way to pass a method name in a generic manner, without passing its parameters, so it can be invoked by the method, with passed arguments?
Consider this example:
public class Client
{
public string Convert(int value)
{
return value.ToString();
}
}
public class Wrapper<TClient>
{
TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, TArg, TResult> action, TArg arg)
{
return action(Client, arg);
}
}
I want to be able to pass to the wrapper the method of TClient I want to invoke, and pass the actual arguments along, all generically:
var wrapper = new Wrapper<Client>();
wrapper.Invoke(c => c.Convert, 5);
Is there any possible way to achieve that, without hard coding the method name, or losing its genericness (i.e. by using Delegate)?
Notes:
The Client is an external sealed class that exposes a gazillion methods each of many parameters. I want wrap its behavior and I don't mind writing all the necessary code in the wrapper, but the usage of the wrapper should be as clean as possible.
Update
I want to avoid the need to specify the parameters. The whole idea is having them inferred from the specified action.
You're very close to getting your code to run. There are two options.
First, you can try this:
public class Wrapper<TClient>
{
public TResult Invoke<TArg, TResult>(Func<TArg, TResult> action, TArg arg)
{
return action(arg);
}
}
Then call it like this:
var wrapper = new Wrapper<Client>();
wrapper.Invoke(wrapper.client.Convert, 5);
Or, alternatively, you can do this:
public class Wrapper<TClient>
{
public Wrapper(TClient client)
{
this.Client = client;
}
private TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, TArg, TResult> action, TArg arg)
{
if (operation.Target != Client)
throw new ArgumentException(nameof(operation));
return action(this.Client, arg);
}
}
And call it like this:
var client = new Client();
var wrapper = new Wrapper<Client>(client);
wrapper.Invoke((c, a) => c.Convert(a), 5);
But, from your description of your problem, I don't see how either of these help and I don't see how to implement what you're asking. Perhaps you need to provide more detail as to what the underlying need you're trying to solve?
You want the expression being passed to Invoke to return a Func that accepts TArg. In code:
public class Wrapper<TClient>
{
TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, Func<TArg, TResult>> action, TArg arg)
{
return action(Client)(arg);
}
}
You can then invoke it like so:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper<Client>();
string result = wrapper.Invoke<int, string>(c => c.Convert, 5);
}
}
Since you don't like the approach of having to explicitly specify type arguments, you can use a slightly different API (which comes with its own annoyances):
public class Wrapper<TClient>
{
TClient Client;
public void Invoke<TArg, TResult>(Func<TClient, Func<TArg, TResult>> action, TArg arg, out TResult result)
{
return action(Client)(arg);
}
}
You can call this like so, with the return type inferred from the out parameter:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper<Client>();
string result;
wrapper.Invoke(c => c.Convert, 5, out result);
}
}
Say you have a Dictionary < string,object > . It might contain decimals, strings or other valid types. It could also contain Actions and Funcs like:
Action<string> or Action<int,int,string> etc.
Is there a general way to discover that a given key k points to an Action or Func and then invoke that same value?
var value = dict[key];
//some sort of predicate checking if value is invokeable
I have considered using the dynamic keyword and simply calling Invoke( args ) on the resulting object, but this seems slow and inelegant.
You could test off it is a delegate:
Delegate d = value as Delegate;
if(d != null) d.DynamicInvoke(args);
However! Knowing what args to provide (in an object-array) is tricky if you don't know the signature ahead of the invoke.
If you don't want to invoke it dynamically via dynamic, or Delegate.DynamicInvoke, you could use some generic extension methods to perform the test for you.
First, make your dictionary a Dictionary<whatever, Delegate> rather than object.
Next, create a couple of extension methods (or more to match the delegate types you care about).
public static bool TryInvoke<T>(this Delegate del, T arg)
{
var action = del as Action<T>;
if (action != null)
{
action(arg);
return true;
}
return false;
}
public static bool TryFunc<T, TResult>(this Delegate del, T arg, out TResult result)
{
result = default(TResult);
var func = del as Func<T, TResult>;
if (func != null)
{
result = func(arg);
return true;
}
return false;
}
Finally, you use your extension methods like so...
var value = dict[key];
if (value.TryInvoke(20))
{
// do something...
}
else
{
int result;
if (value.TryInvoke(20, out result))
{
// do something else...
}
}
It's not hard to imagine building this up as a small library and re-using it.
Are there built in methods for converting between the various types of Func delegates? That is, suppose you need a Func, but you have a Func (and you have the value that should be passed in for the T parameter). For example:
static TREsult Foo<TResult>(Func<TResult> f)
{
// ...
TResult result = f();
// ...
return result;
}
static int MyFunc(int i)
{
return i;
}
void CallFoo()
{
Func<int> func = ConvertFunc(MyFunc, 1); // Does this family of methods exist?
int j = Foo(func);
}
I've written my own, like this:
static Func<TResult> ConvertFunc<T, TResult>(Func<T, TResult> f1, T t)
{
return () => f1(t);
}
static Func<TResult> ConvertFunc<T1, T2, TResult>(Func<T1, T2, TResult> f2, T1 t1, T2 t2)
{
return () => f2(t1, t2);
}
// etc.
But I'm wondering if a family of methods like this exists (or even if there's a better way to do this).
Essentially, I'm doing this for a case where there is some boiler plate code in a method followed by a function call (where the number and types in the function will vary, but the return type is the same), followed by more boiler plate code.
All opinions welcome! Thanks.
static Func<TResult> ConvertFunc<T, TResult>(Func<T, TResult> f1, T t)
{
return () => f1(t);
}
This kind of code to me looks a bit dangerous - not that by itself is anything wrong but need to be careful. You are using closure to embed an input variable in the function. But this could lead to difficult bugs since if the variable changes between converting Func and running it, the result would be different.
I am just curious what would be the benefit. Are you trying to hide away input parameter from the consumer of the function? As long as the variable is a local one passed to it, would be fine.
In terms of a solution, there would not be one since .NET has created 16 different generic Func<> exactly for the same reason.
You can perhaps use reflection to implement a solution but you would be paying a penalty for calling the functions. MethodInfo.GetGenericArguments() would give you the types and you then can use MethodInfo.MakeGenericMethod() to create new ones.
Update
Just to illustrate my point:
static int Double(int number)
{
return number * 2;
}
static void Main(string[] args)
{
int i = 2;
Func<int> f = () => Double(i);
i = 3;
Console.WriteLine(f()); // prints 6 and not 4
}
How can I supply a func to a method, so I could write something like:
MethodTest(a => a.IsAltTagAvailable);
Where the signature of this method takes a func which returns an object (say HtmlImage) when the condition is met (basically just a predicate).
Edit: I need to pass the type I will be working on as T (Parameter). I forgot to do this, how clumsy!
Thanks
A predicate tends to return bool, not an object. What are you going to return when the condition isn't met? Given your example, you don't really mean the function returns an object - you mean it takes an object and returns a bool.
Note that if you're going to have a parameter in the lambda expression, you'll need to use a delegate which takes parameters too.
We really need more information before giving a definitive answer, but you might want something like:
void MethodTest(Func<HtmlImage, bool> predicate)
or
void MethodTest(Predicate<HtmlImage> predicate)
(Personally I like the descriptive nature of using a named delegate, but others prefer to use Func/Action for almost everything.)
That's assuming that the type of input is fixed. If not, you might want to make it a generic method:
void MethodTest<T>(Predicate<T> predicate)
void MethodTest(Func<HtmlImage> func) {
}
void MethodTest(Func<HtmlImage, object> func)
{
}
HtmlImage is the argument of the function (x), object the return value, you could take the concrete type if you want to specify it.
void MethodTest(Func<HtmlImage, bool> func)
Which is a predicate:
void MethodTest(Predicate<HtmlImage> func)
To make it fully generic, replace HtmlImage with a generic argument:
void MethodTest<T>(Predicate<T> func)
public void MethodTest(Func<HtmlImage> delegate)
{
//do what you want
}
OR:
public delegate HtmlImageTagHandler(HtmlImage image);
public HtmlImage MethodTest(HtmlImageTagHandler handler, HtmlImage image)
{
return handler(image) == true ? image : null;
}
use:
MethodTest(a => a.IsAltTagAvailable, a);