Passing delegate function with extra parameters - c#

I have a delegate which looks like the following:
public delegate bool ApprovalPrompt(ApprovalType type, int receipt, params string[] info);
I accept a delegate of this type as a parameter to the function I want to call. However, in one particular calling function, I want to pass some extra data to the function which matches this delegate.
Here's the signature of the implementing function:
private static bool LogApprovalNeeded(FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)
and it's being called as follows:
PrepareReceipt(LogApprovalNeeded);
I'd like it to be:
private static bool LogApprovalNeeded(Customer cust, FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)
which ideally would be used as follows:
PrepareReceipt(LogApprovalNeeded(myCustomer))
How can I accomplish such a thing? I'd rather not need to declare a field in the class just to hold the Customer parameter between one function and the callback...

You can use a lambda to "curry" your function:
PrepareReceipt((type, receipt, info) =>
LogApprovalNeeded(myCustomer, type, receipt, info))
Currying a function is the formal term for storing a reference to a function but with one or more of the parameters "fixed", thus altering the signature of the method.
You can also use a lambda when the signature of your function doesn't need all of the arguments that the delegate is providing; you can effectively discard parameters by not passing forward all of the arguments in the lambda.

You can use a lambda to achieve what you need.
PrepareReceipt((type, receipt, info) =>
LogApprovalNeeded(myCustomer, type, receipt, info));
Alternatively, change your LogApprovalNeeded signature to:
static bool LogApprovalNeeded(ApprovalType type, int receipt,
Customer cust = null, params string[] info)
{
}
But it could get a bit confusing, considering that you already have a variable number of parameters defined after cust.
EDIT: As Servy rightfully pointed out, the change of signature won't let you call the method as you described. If you move the logic related to Customer to PrepareReceipt, though, you won't need to use the above approach (which basically generates a new anonymous method and wraps myCustomer in a closure.

If you need generic solution for delegates partial application (parameters reduction) take a look to the NReco Commons open source library, it contains PartialDelegateAdapter that can do that for any delegate type:
var logApprovalForCustomer = (new PartialDelegateAdapter(LogApprovalNeeded,
new[] {myCustomer})).GetDelegate<Func<FraudFilterUtilities.ApprovalType,int,string[],bool>>();
in this example 1st parameter is fixed with myCustomer value. In addition it also tries to harmonize argument types in runtime.

You can change the PrepareReceipt function to take an additional parameter. The signature would look something like public void PrepareReceipt(Customer customer, ApprovalPrompt approvalPrompt) to accomplish this.

You can't pass it to that delegate as the delegate does not declare an argument of type Customer. The "simple answer" would be to change the signature of the delegate to take the new argument.
That said, that would also require modification of all the consumers of the delegate.

Related

Is it possible to simply pass a generic method with generic parameters as an argument to another method in C#?

For a test, I want to create a generic "helper" method which will take take two arguments, the first argument is a function (or a reference to the function) and the 2nd argument is a list of objects for that function that are to be called as its parameters.
The following does this perfectly:
CallMyFunctionWithParamsPlease(new Func<int, int>(MyMethod), new object[] {1});
public static int CallMyFunctionWithParamsPlease(Delegate func, params object[] args)
{
func.DynamicInvoke(args);
return 3;
}
The thing is, this doesn't look very nice when calling it and I wish to abstract it into another method to act as syntatic sugar.
Ideally I want it to be called like this:
CallMyFunctionWithParamsPlease(myMethod, new Object[] {1});
From what I can gather, there is no elegant solution to do this in C# since I cannot pass myMethod by itself as a reference anywhere, instead I must pass it by declaring a new Func along with the return type of the method. Since I'm not using this return type anywhere, I'm not sure why it's necessary to input this information. My limited understanding is that because C# is statically typed, the compiler must know everything and things like this just aren't possible.
Is this true or not? How would I create syntatic sugar to simply pass a method to another method which can be called there without needing to invoke "new Func"? I would have thought simply passing the function as a reference pointer would allow me to do this, but I'm having difficultly doing this too. I looked into delegates, using "unsafe" with pointers, and a few other options. None of them seem to make this possible, or if they do, they didn't explain it in a manner that I could understand.
I simply want to pass a method to another method, and invoke it with a variable list of object params with variable length whereby I don't need to specify this whilst invoking it. I'm not sure if I'm trying to force C# to do something it's not meant to do here, and instead I'd be better off using a dynamically typed language to do this. The problem is I really enjoy the intellisense that the static typing of C# offers, along with the performance improvements over a language like Python. I'd just like a way to syntactically abstract away the boilerplate with my own helper methods for things like this.
UPDATE: Thanks to the comments here it seems I can do this with a lambda expression nice and elegantly. The signature can be simply changed to public static long CallMyFunctionWithParamsPlease<T>(Func<T> func)
If deferred execution is what you want simply pass a Func<TReturnType> to your method (or class). The calling method doesn't need to know how many parameters are involved.
e.g. Assuming MyMethod has a signature int MyMethod(int arg):
CallMyFunctionWithParamsPlease(() => MyMethod(1));
public static int CallMyFunctionWithParamsPlease(Func<int> func)
{
return func();
}
If MyMethod takes two parameters, it's the same call:
CallMyFunctionWithParamsPlease(() => MyMethod(1, 2));

Generic Callbacks in C#

I want to write a wrapper for the System.Web.Caching.Cache, which handles my cache requests.
I need a method, which can invoke a callback method, if the cache entry doesn't exist. The problem is: I dont know how many params the callback method has:
public T Get<T, TCallback>(string key, TCallback func) where TCallback : Func<T>
{
// check cachekey, do sth
T result = func.Invoke();
return result;
}
With this implementation it's possible to give a callback without params. But what if I have some?
Thanks,
trial
This method should only accept the parameters that this implementation wants to send to a given function. If it has no information that would be relevant to such a callback then it should simply require a parameter-less delegate. If it has parameters that will be needed for some, but won't be needed for others, it should provide them in all cases, using a single delegate.
It then becomes the responsibility of the caller to match the function that they want to call with the signature of the delegate. If they want to fix values for some function that has parameters your callback doesn't have, or if they want to call a function with less parameters, etc. it is their responsibility to make the "conversion", rather than this method's responsibility to deal with a delegate with an unknown signature.
The use of lambdas makes "converting" functions very easy; much easier than the alternative. To fix a value for a parameter when your callback doesn't have one, you can close over the variable:
int value = 5;
Get("key", () => SomeMethod(value));
You can also use a lambda to ignore a parameter:
Get("key", someParameterToIgnore => AnotherMethod());
1) You can use dynamic or Dictionary as parameter of your callback. Put in Dictionary or dynamic string value - like CallbackType.
Its bad because you lost static type analysing, but it possible.
2)It may be useful: Ellipsis notation in C#?

Best way to pass delegate parameters

What is the best way to pass parameters through to a delegate? I can see benefits for both of the following ways so I would like to know the most used and industry accepted way of doing it:
1) Pass any parameters individually with each parameters being just that, a parameter.
Example Delegate
public delegate void MyDelegate(bool PARAM1, String PARAM2, int PARAM3);
2) Pass any parameters through a struct and the only parameter of the delegate is that struct.
Example Struct
public struct MyDelegateArgs
{
public bool PARAM1;
public String PARAM2;
public int PARAM3;
}
Example Delegate
public delegate void MyDelegate(MyDelegateArgs args);
Imagine your struct had 20 properties / fields - would you really want to pass all of those in as parameters? Generally I would argue to hide all of this complexity and keep your code DRY by passing in a class / struct instead - this in most cases is also more expressive - your delegates needs a parameter of type MyDelegateArgs.
The only argument I could come up with for passing in individual values is if you only need a small subset that just happen to be used in MyDelegateArgs but are otherwise unrelated.
If your delegate has utility as an Action<T> or a Predicate<T>, using the struct argument is preferable as it will keep you from tripping over a case where the signature gets too large for the predefined Action or Predicate definitions when you go to extend the delegate's signature.

function overload

Can I have two same function name with same parameters but different meaning.
For example:
public void test(string name)
public void test(string age)
Thank you.
No, you can't. The signature is not different - it doesn't matter what the parameter names are.
Methods are declared in a class or struct by specifying the access level such as public or private, optional modifiers such as abstract or sealed, the return value, the name of the method, and any method parameters. These parts together are the signature of the method.
http://msdn.microsoft.com/en-us/library/ms173114.aspx
Like a few other answers have stated, consider the type of data you're taking in. Name is indeed a typical string, but does age have to be? If you allow it to be a - for example - int then you can overload your method as you wish.
No, you cannot overload on a return type or a parameter name. Unlike some other languages (most notably, Objective C1) parameter name is not part of the signature of your function.
The signature of a method consists of the name of the method and the type and kind (value, reference, or output) of each of its formal parameters, considered in the order left to right. The signature of a method specifically does not include the return type, nor does it include the params modifier that may be specified for the right-most parameter.
1 even there it's not exactly the parameter name that becomes part of the selector.
You can have static and non-static methods with the same name, but different parameters following the same rules as method overloading, they just can't have exactly the same signature.
No.
Signatures and Overloading
If you need a method with different meaning why won't you create a method with a different name? It would be confusing to use the same method name for different things on the same object.
You could mix together these methods using optional parameters and default values:
public void test(string name = null, string age = null)
{
if (name != null)
{
// Do something
}
else if (age != null)
{
// Do something else
}
}
And you could call this method like that:
test(name: "John");
test(age: "30");
Not very clean, but still useable.
No - the compiler throws an error because compiler use parameters to detemine which method to call, not the return type.
NO.
An OVERLOADED FUNCTION must have different SIGNATURE.
i.e.- arguments should be different, either in terms of number of arguments or order of different datatypes arguments.

C# function that takes pointer to function as an in parameter without declaring any specific delegate types?

I want to implement a method that will find stuff in my custom class. It should work like generic collections work - i pass a pointer to a function, and the method will iterate through all it has to look in, apply this function, and if it returns true return the found item.
I'd like to pass function pointer as a parameter, but i dont want to declare delegate types.
I know i can do something like:
delegate bool Foo(MyClass)
MyClass MyMethod(Foo x)
{...}
And i know i can do something like this:
MyClass MyMethod(Func<MyClass,bool> x)
But can i do it without declaring a delegate type and without using built in stuff like Func<> which has limits on how many parameters i can have (in case of Func, one...)
You can just use delegate if you want, although it's a bit old school :)
public void TestInvokeDelegate()
{
InvokeDelegate( new TestDelegate(ShowMessage), "hello" );
}
public void InvokeDelegate(TestDelegate del, string message)
{
del(message);
}
public delegate void TestDelegate(string message);
public void ShowMessage(string message)
{
Debug.WriteLine(message);
}
You can allways pass in a Delegate and call DynamicInvoke on it:
MyClass MyMethod(Delegate x) {
// ...
x.DynamicInvoke(....);
// ...
}
It looks like you are trying to implement the Visitor pattern. In this case visiting methods usually have only one parameter - the instance to visit. Having additional arguments passed around conceals the use of the pattern and makes it harder to reason about. This article shows you one way to implement it in C#.
The key is to create a visitor class that will encapsulate all the parameters that affect the visiting process. This way you don't need to pass anythnig other than an object in question in the visiting method - everything else lives in instance fields.
However, if you really want to pass some additional parameters in the method and don't know what type they can have, there are ways to do that. More or less standard approach in .NET world is to use a delegate without return value and with single parameter of type object, the example would be ParameterizedThreadStart delegate:
public delegate void ParameterizedThreadStart(
Object obj
)
This way you get to pass only one parameter in the delegate, but it could be anything - an instance of a class, an array or null, if you end up not needing additional arguments after all. The downside of this approach is that it requires type casting which can lead to runtime errors.

Categories