How can I use a function delegate with an optional parameter [duplicate] - c#

I have the following method in an assembly:
public string dostuff(string foo, object bar = null) { /* ... */ }
I use it as a callback, so a reference to it is passed to another assembly as such:
Func<string, object, string> dostuff
Now in the original form, I can call it without specifying that second argument, which defaults to null. But when I use it as a callback in that second assembly, I must specify that second argument.
What syntax allows me to ignore that second argument?

You'll need to create a new method that accepts only one argument, and that passes the default value for the second argument. You could do this with a lambda, rather than creating a new named method, if you wanted:
Func<string, string> doStuffDelegate = s => dostuff(s);
The other option would be to use a delegate who's signature has an optional second argument, instead of using Func, in which case your method's signature would match:
public delegate string Foo(string foo, object bar = null);
You could assign dostuff to a delegate of type Foo directly, and you would be able to specify only a single parameter when invoking that delegate.

You can't do this, simply because optional arguments are syntactic sugars and can be only used if you are calling the method directly. When you call the method like this:
dostuff(foo);
Compiler translates it into:
dostuff(foo, null);
In other cases such as using a delegate that doesn't accept an optional argument or when calling this method using reflection, you have to provide the optional argument.

Related

How to create a compatible delegate from its type?

I'm trying to create a Standard library with common types for WPF/UWP etc.
Since many types are not in Standard, sometimes you have to use reflection.
In this connection, the task of creating a DispatchedHandler from an Action arose.
In UWP, this is easy: new DispatchedHandler(action);.
But in Standard I only have Type from DispatchedHandler.
private object GetDispatchedHandler(Action action)
{
// Some code
dispatchedHandlerType = windowsAssembly.GetType("Windows.UI.Core.DispatchedHandler");
// Next, you need to transform the `action` and return it from the method.
return Activator.CreateInstance(dispatchedHandlerType, action);
}
This code throws an exception: "Constructor on type 'Windows.UI.Core.DispatchedHandler' not found".
But can get a constructor from a type: dispatchedHandlerType.GetConstructors()[0].
The constructor has the following signature: {Void .ctor(System.Object, IntPtr)}.
The first parameter, I think, should be passed action.
What should be passed as the second parameter?
dispatchedHandlerConsructor.Invoke(new object[] { action, ??? });
DispatchedHandler is a delegate type. It doesn't take an Action; it basically is the same thing as Action, but in an incompatible delegate type. The parameters here are the target instance and the function-pointer. You can create arbitrary delegate instances via Delegate.CreateDelegate. Usually you would create this type directly from a target method and instance, and never create the Action, however in this case you may also be able to simply pass in the .Target and .Method from the Action into your call to Delegate.CreateDelegate, since the signature is the same:
var del = Delegate.CreateDelegate(dispatchedHandlerType, action.Target, action.Method);

Method called without passing parameters

I'm a beginner in C#. I encountered below code snippet in my project. I do not understand how ViewHelper.IsInView has been called without passing any parameters. Could anyone explain me this. Thanks in advance.
public static class ViewHelper
{
public static bool IsInView(IFrameworkElement element)
{
----------
}
}
var Result = Views.Any(ViewHelper.IsInView);
The Any method accepts a delegate - a pointer to a function - of the form Func<T, bool>. Meaning it expects a method that accepts an element of the type of the collection (I'm guessing IFrameworkElement in your case) and returns a bool - which is exactly the signature of the IsInView method.
The Any method then executes this delegate on elements in the Views collection until it encounters one that returns true.
In C#, there is an implicit conversion from a "method group" to a delegate type. Essentially, when you write
Views.Any(ViewHelper.IsInView)
It translates into
Views.Any(new Func<IFrameworkElement, bool>(ViewHelper.IsInView))
What is being passed to Enumerable.Any is a delegate, the method is not being called at this point. If there are any views then Any will call that delegate with one or more of the views as the argument.
The delegate you're passing to Any has been created through something known as implicit method group conversion.
Views.Any is expecting a delegate of the type Func<IFrameworkElement, bool>, meaning it takes a single parameter of type IFrameworkElement and returns bool. You can create such a delegate from your method, as the signatures are compatible. This is how you would explicitly do this:
Func<IFrameworkElement, bool> predicate =
new Func<IFrameworkElement, bool>(ViewHelper.IsInView);
However, from C# 2.0 such a conversion can be done implicitly, meaning this code is exactly the same:
Func<IFrameworkElement, bool> predicate = ViewHelper.IsInView;

C# lambda expressions without variable / parameter declaration?

What's it called when a method that takes a lambda expression as the parameter, such as Enumerable.Where, is invoked without actually declaring a variable or method parameter in the expression?
For example, I'm familiar with this lambda expression syntax:
public string GetDigits(string input)
{
return new String(input.Where(i => Char.IsDigit(i)).ToArray());
}
However, I was surprised to find out that this can also be written as:
public string GetDigits(string input)
{
return new String(input.Where(Char.IsDigit).ToArray());
}
What's going on in that second snippet, where the Char.IsDigit() method is (apparently) being called with an implicit parameter? What is this syntax called?
Methods don't accept lambdas as parameters. They accept delegates as parameters. A lambda is just one way of creating a delegate.
Another way is supplying a method group, as is done in your second example, which can be converted to a delegate.
A similar way is to use the anonymous method feature. This was more or less replaced with lambdas when they were added though, so you don't see it much. Your example using that syntax would be:
Func<char, bool> predicate = delegate(char c) { return Char.IsDigit(c); };
Yet another way would be to create a delegate using Delegate.CreateDelegate. (This isn't something you see all that often though.)
A final way is to have a delegate variable that you got from somewhere else. (That somewhere else would have created the delegate using one of these other options.)
What's going on in that second snippet, where the Char.IsDigit() method is (apparently) being called with an implicit parameter? What is this syntax called?
It's not being called. That's the whole point. We're trying to create a delegate. A delegate is an object that keeps track of a method to be invoked, and an object that it should be invoked on. You can then invoke the delegate and it will call the method that was used to create it. So here you're not calling IsDigit, you're creating a delegate that is pointing to the IsDigit method, and that will call it whenever that delegate is invoked.
When you use a lambda you're creating a new method, possibly in a new class, (neither of which have a name you can refer to, but they'll have one at runtime) and the body of that anonymous method will call IsDigit. The lambda then resolves to a delegate pointing to that anonymous method, which maintains the semantics of the other example of having a method that when called, calls an anonymous method which, in its implementation, calls IsDigit. It's adding an extra layer of indirection (that may or may not just get optimized out at runtime) to accomplish the same thing.
The signature of Enumerable.Where is:
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
This:
input.Where(i => Char.IsDigit(i))
is equivalent to writing:
Func<char, bool> temp = i => Char.IsDigit(i);
input.Where(temp);
so it creates an anonymous function with a parameter i that calls Char.IsDigit.
This:
input.Where(Char.IsDigit)
is equivalent to
Func<char, bool> temp = Char.IsDigit;
input.Where(temp);
that is equivalent to:
Func<char, bool> temp = new Func<char, bool>(Char.IsDigit);
input.Where(temp);
so it creates a delegate to Char.IsDigit and then passes it to input.Where.
So the second one removes the "man-in-the-middle" (the anonymous function). In this particular case it is "legal" because the i parameter of the anonymous function is passed "as is" to Char.IsDigit. It would have been different if it was:
input.Where(i => !Char.IsDigit(i))
in this case, you can't remove the man-in-the-middle (the anonymous function).
There is no name for all of this (or you could call the first "creating and passing a delegate to an anonymous function" and the second "creating and passing a delegate created from a method group"... but they aren't beautiful catchphrases, they are more a description of what you are doing)
Because the compiler will implicitly cast the method group to a delegate if it finds a single method that matches the expected signature, in this case a delegate taking a single char as input and returning a bool.
Your Where expects a Func<char, bool>, which is a delegate for methods that take a char argument and return a bool. Anything that matches this delegate is a valid argument for this Where.
The lambda you wrote initially matches this delegate by type inference: the compiler expects that i is char, based on the generic parameter of the enumerable source - and infers the return type as bool, because that's what the method call expression inside the lambda would return.
The Char.IsDigit method itself also matches this. Thus, referencing the method is another valid way of expressing the same thing. This is called a method group.
The semantic equivalence of these two possible arguments for Where also makes sense if you consider that for every lambda expression, the compiler generates an anonymous method and then passes that anonymous method where the delegate was expected.
To illustrate this, consider your original snippet:
Where(i => Char.IsDigit(i))
The above gets lowered by the compiler to:
bool AnAnonymousMethod(char i)
{
return Char.IsDigit(i);
}
and then:
Where(AnAnonymousMethod)
As you can see, the lambda syntax (in cases where you don't have captured variables, like here) is just syntactic sugar for writing an anonymous method and then using the method group of this newly written method as the argument wherever a compatible delegate is expected.

Passing variable arguments to a delegate

I have the following delegate:
public delegate object DynamicFunction(dynamic target, params object[] args);
However, when I try to create it:
DynamicFunction func = new DynamicFunction((t) => {
//Handle t
});
The compiler throws an error saying that the delegate does not take 1 argument, even though I specified the last argument to be of type params object[].
If I pass exacly one extra argument to the delegate, it works.
For example:
DynamicFunction func = new DynamicFunction((t,a) => {
//Handle t
});
However, I don't want to specify that extra argument, as I intentionally wanted those arguments to be optional.
What is happening here?
params mean that compiler will do smart thing when you call the function to convert whatever arguments you've passed to array.
It does not mean that function itself takes 1 or 2 parameters, and it does not mean there are 2 version of function f(dynamic target) and f(dynamic target, params object[] args).
Note that you still want to be able to call
func (1);
func(1, optional1, optional2);
So your delegate need to handle both.
When invoking the delegate the caller can provide 1...n arguments. What you're doing now isn't invoking the delegate, but rather assigning a compatible method to a delegate of that type. When doing so you need to provide exactly two arguments (of the appropriate type), because that's what the delegate's definition states it must accept.

What does this c# syntax mean?

Hi
I have a little problem with understanding this kind of syntax
public delegate void DelegateType();
BeginInvoke(new DelegateType(functionName));
Could somebody tell me what exectly mean new DelegateType(functionName). Why do I have to use new keyword ??
See the documentation.
A delegate is a type that holds a method.
You're creating a new instance of a delegate type, pointing to an existing method.
C# 2 adds an implicit conversion from a method group to any matching delegate type.
However, since BeginInvoke doesn't take a specific delegate type (such as System.Action), you always need to explicitly create a delegate instance.
The first statement declares a delegate type, the second statement instantiates a new delegate of DelegateType.
From the corresponding MSDN article (read the article for more information!):
Once a delegate type has been
declared, a delegate object must be
created and associated with a
particular method. Like all other
objects, a new delegate object is
created with a new expression. When
creating a delegate, however, the
argument passed to the new expression
is special — it is written like a
method call, but without the arguments
to the method.
public delegate void DelegateType();
This defines the syntax for a delegate. This is a reference to a method, either static, or an instance method.
When you call BeginInvoke, you're passing a delegate as the parameter. The C# compiler will convert from any explicit delegate type to System.Delegate, but since the parameter is defined as taking any delegate (via System.Delegate), you must explicitly define the type.
When you specify:
new DelegateType(functionName)
You're creating a delegate of a specific type (DelegateType), which is then passed to the function.
Often, newer APIs will use a known type, such as System.Action (which has the same syntax as your DelegateType). If a method takes an "Action", you would not need the definition above, and you could do:
CallMethodTakingAction(functionName);
'DelegateType' is only a type of thing, so like any other type, you want to say "here's one instance of this type", you need to use 'new'.

Categories