I've used short.Parse(somestring) in the past. But recently I've seen a confusing usage of short.Parse() like below:
var shortArray = Array.ConvertAll(stringArr, short.Parse);
So, Array.ConvertAll expects an array and a converter. Well, fine! But how are we passing the short.Parse as (or like) a property? I don't find such a property in Int16 struct. So, what is happening here actually?
Array.ConvertAll takes an instance of a Converter<TIn, TOut> delegate as its second parameter. The signature of this delegate is substantially the same as short.Parse - both return a value for a single argument.
The compiler will convert a 'method group' to a compatible delegate. This is known as implicit method group conversion.
For comparison, the explicit creation of the delegate would look like this:
Array.ConvertAll(stringArr, new Converter<string, short>(short.Parse));
So, to answer you question: it's still a method, not a property. What you are doing here is passing the method as a delegate. You are providing ConvertAll with a function to call: when it converts an element in the source array, it will execute short.Parse(element) and use the value returned in the new array.
short.Parse is a method. But it is possible to pass a method as an argument.
Note the difference between calling a method and passing the value returned by that method (short.Parse()), and passing the method itself (short.Parse).
Internally, this would be passing the address of the method so that the receiver of that argument can call it.
Related
I'm curious why neither of the following DoInvoke methods can be called with only one params:
public class foo {
private void bar(params object[] args) {
DoInvoke(args);
}
//Error: There is no argument given that corresponds to the required formal parameter 'args' of 'foo.DoInvoke(Delegate, object[])'
private void DoInvoke(Delegate d, object[] args) {
d.DynamicInvoke(args);
}
//Error: Argument 1: cannot convert from 'object[]' to 'System.Delegate'
private void DoInvoke(Delegate d, params object[] args) {
d.DynamicInvoke(args);
}
}
I already found a way that doesn't abuse params. I'm curious why params are not expanded here.
I was able to do something similar in Lua, hence my attempt. I know Lua is far less strict, but I'm not sure which C# rule I'm breaking by doing this.
I'm curious why neither of the following DoInvoke methods can be called with only one params:
Short version: the first can't, because it has two non-optional parameters and because you're passing a value of the wrong type for the first non-optional parameter. The second can't, but only because the value you are trying to pass for the single non-optional parameter is of the wrong type; the second parameter is optional and so may be omitted as you've done.
You seem to be under the impression that in your method declaration private void bar(params object[] args), the presence of the params keyword makes the args variable somehow different from any other variable. It's not. The params keyword affects only the call site, allowing (but not requiring) the caller to specify the array elements of the args variable to be specified as if they were individual parameters, rather than creating the array explicitly.
But even when you call bar() that way, what happens is that an array object is created and passed to bar() as any other array would be passed. The variable args inside the bar() method is just an array. It doesn't get any special handling, and the compiler won't (for example) implicitly expand it to a parameter list for use in passing to some other method.
I'm not familiar with Lua, but this is somewhat in contrast to variadic functions in C/C++ where the language provides a way to propagate the variable parameter list to callees further down. In C#, the only way you can directly propagate a params parameter list is if the callee can accept the exact type of array as declared in the caller (which, due to array type variance in C#, does not always have to be the exact same type, but is still limited).
If you're curious, the relevant C# language specification addresses this in a variety of places, but primarily in "7.5.1.1 Corresponding parameters". This reads (from the C# 5 specification…there is a draft C# 6 specification, but the C# 5 is basically the same and it's what I have a copy of):
For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.
It goes on to describe what "parameter list" is used to validate the argument list, but in your simple example, overload resolution has already occurred at the point this rule is being applied, and so there's only one parameter list to worry about:
• For all other function members and delegates there is only a single parameter list, which is the one used.
It goes on to say:
The corresponding parameters for function member arguments are established as follows:
• Arguments in the argument-list of instance constructors, methods, indexers and delegates:
o A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter. [emphasis mine]
o A positional argument of a function member with a parameter array invoked in its normal form corresponds to the parameter array, which must occur at the same position in the parameter list.
o A positional argument of a function member with a parameter array invoked in its expanded form, where no fixed parameter occurs at the same position in the parameter list, corresponds to an element in the parameter array.
o A named argument corresponds to the parameter of the same name in the parameter list.
o For indexers, when invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
In other words, if you don't provide a parameter name in your argument list, arguments correspond to method parameters by position. And the parameter in the first position of both your called methods has the type Delegate.
When you try to call the first method, that method has zero optional parameters, but you haven't provided a second parameter. So you get an error telling you that your argument list, consisting of just a single argument (which by the above corresponds to the Delegate d parameter), does not include a second argument that would correspond to the object[] args parameter in the called method.
Even if you had provided a second argument, you would have run into the same error you get trying to call your second method example. I.e. while the params object[] args parameter is optional (the compiler will provide an empty array for the call), and so you can get away with providing just one argument in your call to the method, that one argument has the wrong type. Its positional correspondence is to the Delegate d parameter, but you are trying to pass a value of type object[]. There's no conversion from object[] to Delegate, so the call fails.
So, what's that all mean for real code? Well, that depends on what you are trying to do. What did you expect to happen when you tried to pass your args variable to a void DoInvoke(Delegate d, params object[] args) method?
One obvious possibility is that the args array contains as its first element a Delegate object, and the remainder of the array are the arguments to pass. In that case, you could do something like this:
private void bar(params object[] args) {
DoInvoke((Delegate)args[0], args.Skip(1).ToArray());
}
That should be syntactically valid with either of the DoInvoke() methods you've shown. Of course, whether that's really what you want is unclear, since I don't know what the call was expected to do.
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;
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.
I'm confused as to why this works:
Action myAction1 = () => myIntFunc();
...
private Int32 myIntFunc() {
return(4);
}
I would expect the compiler to not allow this because an Action represents functions that do not return parameters, yet myIntFunc clearly returns a parameter.
As further evidence, note that this does not work:
Action myAction2 = myIntFunc;
So it's like the lambda syntax is letting me get away with something I shouldn't be able to get away with. I'm guessing I'm overlooking something to do with how Actions and lambdas work together...??
I think its the same than when you do this:
myIntFunc();
Ignoring the result of the method.
What you're trying to do is explicitly allowed. Per the MSDN documentation on the Action delegate (emphasis added):
The encapsulated method must have no parameters and no return value. (In C#, the method must return void. […] It can also be a method that returns a value that is ignored.)
In the C# language specification, paragraph 6.5, one of the bullets says: If D has a void return type and the body of F is an expression, when each parameter of F is given the type of the corresponding parameter in D, the body of F is a valid expression (wrt §7) that would be permitted as a statement-expression (§8.6).
So it's OK to throw away the return value in that case.
For a method group conversion, see paragraph 6.6 instead. Then the method must be compatible including the return type.
So there's a difference between anonymous method (lambda) and normal (named) method (or method group).
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'.