Cannot convert from 'method group' to 'System.Action<object>' error - c#

I have created the following function:
public void DelegatedCall(Action<Object> delegatedMethod)
And defined the following method
public void foo1(String str) { }
However, when I try to call DelegateCall with foo1:
DelegatedCall(foo1);
...I get the following compiler error:
Argument 1: cannot convert from 'method group' to 'System.Action<object>'
What is the reason for this error and how can I correct it? Unfortunately, casting foo1 to Action is not an option.

DelegatedCall expects a delegate that takes any object as an argument. But your function foo1 that you are passing to DelegatedCall can only cope with a string argument. So, the conversion isn't type-safe and thus is not possible.
Input parameters are contra-variant, but your code needs covariance. (See Difference between Covariance & Contra-variance.)
You can make DelegatedCall generic:
DelegatedCall<T>(Action<T> action)
...or have it take any delegate:
DelegatedCall(Delegate action)
But then implementing it is ugly and requires reflection. It also doesn't verify that the function has only one parameter at compile-time.

Variance doesn't work that way around; you would need
DelegatedCall(obj => foo1((string)obj));
As even in 4.0 it won't believe that every object is a string.
Note that if it was foo1(object) and Action<string> (i.e. the other way around) it probably would work (in 4.0), since every string is an object.

Related

Calling a generic method

Suppose I have a generic method. What is the difference between calling the method with specifying the type and calling without it.
When does it become mandatory to specify the type?
Write(1);
Write<int>(1);
Write<string>("test");
Write("test");
private static void Write<T>(T param)
{
Console.WriteLine(param);
}
The compiler will attempt to resolve the type argument at compile time. In cases where this is possible, it is done automatically without you have to specify an explicit type. In all other cases, when the compiler is unable to determine the type argument, the compiler will throw an error and you cannot compile your application.
In your example Write(1), the argument 1 is of type int. So the compiler infers that T must be int, so the call is equivalent to Write<int>(1). Similarly with Write("test"), "test" is of type string, so the compiler will infer that T is string.
This generally works on the compile time type of the argument you pass to the function. So if you have a string with a compile time type of object, T would be object:
object arg = "foo";
Write(arg); // arg is object
// this is equivalent to this:
Write<object>(arg);
So although you are passing a string, its compile time type is object so that’s the only information, the compiler is able to use here.
In addition, you might want to specify the type argument explicitly whenever you want the compiler to use a different type than the compile time argument of what you’re passing to it. In the above example, you could use Write<object>(1) which would cause the integer 1 to be casted into object. However, in practice this usually defeats the purpose of generic methods and may have actual consequences even if you don’t need to access the actual parameter’s compile time type. For example, value types would be boxed when passed as object but generic methods allow you to keep them as value types—remember that a generic method definition (same applies to types) is kind of equivalent to specifying an overload with every other valid generic type argument value (so you usually have an infinite copy of methods).
Of course, the compiler’s type inference also works with multiple arguments:
void Write<T1, T2>(T1 arg1, T2 arg2)
{ … }
Write(1, "foo");
// is equivalent to
Write<int, string>(1, "foo");
However, when the compiler is not able to infer even one type argument, you will have to specify all of them in the call.
It's not mandatory in this situation because the parameter param is the generic (the compiler resolves it like that).
That means it's mandatory whenever the type argument is not supplied as a parameter.
It becomes mandatory to specify the type when the compiler cannot infer it, or when you are not happy with what the compiler infers.
There are no difference between
Write<string>("test");
Write("test");
But, there difference, when you specify not exactly type of parameter, but convertible, for example
Write<object>("test");
Write("test");
Just try to print type parameter and will see difference
private static void Write<T>(T param)
{
Console.WriteLine(typeof(T));
Console.WriteLine(param);
}

inference from methods are not allowed? [duplicate]

Given this code:
class C
{
C()
{
Test<string>(A); // fine
Test((string a) => {}); // fine
Test((Action<string>)A); // fine
Test(A); // type arguments cannot be inferred from usage!
}
static void Test<T>(Action<T> a) { }
void A(string _) { }
}
The compiler complains that Test(A) can't figure out T to be string.
This seems like a pretty easy case to me, and I swear I've relied far more complicated inference in other generic utility and extension functions I've written. What am I missing here?
Update 1: This is in the C# 4.0 compiler. I discovered the issue in VS2010 and the above sample is from a simplest-case repro I made in LINQPad 4.
Update 2: Added some more examples to the list of what works.
Test(A);
This fails because the only applicable method (Test<T>(Action<T>)) requires type inference, and the type inference algorithm requires that each each argument be of some type or be an anonymous function. (This fact is inferred from the specification of the type inference algorithm (§7.5.2)) The method group A is not of any type (even though it is convertable to an appropriate delegate type), and it is not an anonymous function.
Test<string>(A);
This succeeds, the difference being that type inference is not necessary to bind Test, and method group A is convertable to the required delegate parameter type void Action<string>(string).
Test((string a) => {});
This succeeds, the difference being that the type inference algorithm makes provision for anonymous functions in the first phase (§7.5.2.1). The parameter and return types of the anonymous function are known, so an explicit parameter type inference can be made, and a correspondense is thereby made between the types in the anonymous function (void ?(string)) and the type parameter in the delegate type of the Test method’s parameter (void Action<T>(T)). No algorithm is specified for method groups that would correspond to this algorithm for anonymous functions.
Test((Action<string>)A);
This succeeds, the difference being that the untyped method group parameter A is cast to a type, thereby allowing the type inference of Test to proceed normally with an expression of a particular type as the only argument to the method.
I can think of no reason in theory why overload resolution could not be attempted on the method group A. Then—if a single best binding is found—the method group could be given the same treatment as an anonymous function. This is especially true in cases like this where the method group contains exactly one candidate and it has no type parameters. But the reason it does not work in C#4 appears to be the fact that this feature was not designed and implemented. Given the complexity of this feature, the narowness of its application, and the existance of three easy work-arounds, I am not going to be holding my breath for it!
I think it's because it's a two-step inference:
It has to infer that you want to convert A to a generic delegate
It has to infer what the type of the delegate parameter should be
I'm not sure if this is the reason, but my hunch is that a two-step inference isn't necessarily easy for the compiler.
Edit:
Just a hunch, but something is telling me the first step is the problem. The compiler has to figure out to convert to a delegate with a different number of generic parameters, and so it can't infer the types of the parameters.
This looks like a vicious circle to me.
Test method expects a parameter of delegate type constructed from generic type Action<T>. You pass in a method group instead: Test(A). This means compiler has to convert your parameter to a delegate type (method group conversion).
But which delegate type? To know the delegate type we need to know T. We didn't specify it explicitly, so compiler has to infer it to figure out the delegate type.
To infer the type parameters of the method we need to know the types of the method arguments, in this case the delegate type. Compiler doesn't know the argument type and thus fails.
In all other cases either type of argument is apparent:
// delegate is created out of anonymous method,
// no method group conversion needed - compiler knows it's Action<string>
Test((string a) => {});
// type of argument is set explicitly
Test((Action<string>)A);
or type parameter is specified explicitly:
Test<string>(A); // compiler knows what type of delegate to convert A to
P.S. more on type inference
You're passing the name of the Method A. The .Net framework CAN convert it to an Action, but it's implicit and it will not take responsibility for it.
But still, a method name is NOT an explicit Action<> Object. And therefor it won't infer the type as an Action type.
I could be wrong, but I imagine the real reason C# cannot infer the type is due to method overloading and the ambiguity that arises. For example, suppose I have the following methods: void foo (int) and void foo (float). Now if I write var f = foo. Which foo should the compiler pick? Likewise, the same problem happens with your example using Test(foo).

Pass Method As EventDelegate

I am attempting to pass a method as a parameter. But I am getting a compiler error and I dont quite understand what I am doing wrong?
The compiler error is:
Argument `#1' cannot convert 'method group' expression to type 'EventDelegate'
public class AssignEventDelegate : MonoBehaviour {
public UISprite sprite;
public void AddOnFinish (EventDelegate method) {
EventDelegate.Add (sprite.GetComponent<TweenScale>().onFinished, method);
}
}
public class AssignEventDelegateOther : MonoBehaviour {
// Use this for initialization
void Start () {
// Compiler error occurs below
GameObject.Find ("Main Camera").gameObject.GetComponent<AssignEventDelegate>().AddOnFinish( myOnFinish );
}
public void myOnFinish () {
Debugger.print ("myOnFinish");
}
}
First let's make sense of the error message. It should be clear that the problematic part of that line is
.AddOnFinish( myOnFinish );
So what's a method group? That has been answered here before. In short, it is what the compiler calls a bare reference to a method name that does not include () or any argument list. You can't use a method group on its own. It does not have any representation in the CLR. Its a method "group" because, at least in theory, it represents a set of methods that the compiler will have to do overload resolution on. The compiler knows how to turn method groups (also lambdas and anonymous methods) into specific delegate types, but that's it. myOnFinish is a method group, but here it really only contains a single method.
A quick look at the NGUI docs tells me that contrary to its name, EventDelegate is not a delegate type but simply a class that is meant to wrap a delegate.
So there we have it. The compiler has no idea how to convert a method group to this EventDelegate class and it produces an error.
To fix it, we need to provide the conversion. Which it turns out, would just be calling the constructor of EventDelegate:
.AddOnFinish( new EventDelegate(myOnFinish) );
This works since the constructor takes an instance of EventDelegate.Callback which is delegate type that is compatible with myOnFinish.
Instead of passing method as argument define the delegate having same signature as method and pass it as argument to function.

Is there a way to cause type inference of the delegate passed to Control.BeginInvoke?

Control.BeginInvoke:
In both cases, it seems clear that the compiler has all the information it needs to infer the delegate type. Yet in neither case does the type inference seem to work:
BeginInvoke(myMethodThatTakesNoParams);
produces the compiler error
Error 105 The best overloaded method match for
'System.Windows.Forms.Control.BeginInvoke(System.Delegate)' has some
invalid arguments
as does
BeginInvoke(ShowProcessErrors, new object[] { process });
Both method calls only compile if I change them to explitly create a delegate and pass that. Both of the following compile fine:
BeginInvoke(new MethodInvoker(myMethodThatTakesNoParams));
and
BeginInvoke(new ProcessErrorDelegate(ShowProcessErrors), new object[] { process });
There doesn't seem to be any obvious reason why type inference won't work here. Is there a way to call BeginInvoke without explicitly creating a delegate?
The issue is that myMethodThatTakesNoParams isn't really a delegate but a so-called "method group" by the compiler. A method group isn't a real type in the CLR. It must be converted to delegate type to be used. When you use a method group like this:
Action a = myMethodThatTakesNoParams;
The compiler recognizes that you want to convert the method group to a delegate and inserts the conversion for you. It produces IL that effectively says:
Action a = new Action(myMethodThatTakesNoParams);
When you say:
Delegate d = myMethodThatTakesNoParams
The compiler doesn't really know what to do. It could theoretically pick any compatible delegate type for you, but C#, in general, does not insert types you did not use into expressions. Since it does not know what delegate you want the method group converted to, the compiler produces an error.
I used variable assignment in my examples, but the same logic applies for parameters to methods.
A work around would be to write your own extension method that has a specific delegate type in it:
static class ControlExtensions
{
public static IAsyncResult BeginInvoke(this Control c, Action a)
{
return c.BeginInvoke(a);
}
}
This usually comes as a surprise to .NET programmers, the C# Language Specific in section 15.1 explains:
Note that System.Delegate is not itself a delegate type; it is a class type from which all delegate types are derived
And of course there is no conversion of a method to a class. The first argument of BeginInvoke() must be a delegate type to keep the compiler happy. Maybe that sounds like an arbitrary limitation, it is most definitely not. A very important property of delegates is that they are type-safe. A pretty big deal in a statically typed language like C#. You can't invoke a delegate with too few arguments, or too many, or arguments of the wrong type. Checked when the delegate is created, you get a compile time error while you are still in your pajamas or the comfort of your cubicle. No surprises at runtime with your program suddenly keeling over at the most inopportune time of the day. This type checking of course cannot work for Delegate. So it is not a delegate type.
This does go wrong with Control.BeginInvoke(), it uses a back-door to get the method invoked. Kaboom when you pass Math.Pi instead of progress, you can't find out until you run the code. Not a pleasant exception either because it is unclear whether you got the BeginInvoke() call wrong or whether the invoked method threw an exception. Actually much more of a problem with Invoke().
Anyhoo, gotta give the compiler a delegate, more than one way to do that:
The venerable anonymous method syntax still works pretty well in this context:
this.BeginInvoke(delegate() { ShowProcessErrors(process); });
You already found MethodInvoker, I usually go for Action since it is shorter:
this.BeginInvoke(new Action(() => ShowProcessErrors(process)));
And you can of course always keep the compiler happy with an extension method:
this.BeginInvoke(() => ShowProcessErrors(process));
with:
static class Extensions {
public static void BeginInvoke(this Control ctl, Action a) {
ctl.BeginInvoke(a);
}
}

Casting to primitive type and using as parameter?

I'm trying to compile a project containing this method;
public void Send<T>(object o) where T : struct {
BinaryWriter bw = new BinaryWriter(stream);
bw.Write((T)o);
}
I inspired from this method (working);
public static T Cast<T>(object o) {
return (T)o;
}
BinaryWriter.Write function supports primitive types for parameters, so I thought I could use it like that. However, Visual Studio says "The best overloaded method match for 'System.IO.BinaryWriter.Write(bool)' has some invalid arguments"
I'm trying to avoid writing a long switch statement containing every primitive type and add a parameter to method for choosing the type. This is ugly and doesn't seem right.
This is simple and elegant:
Send< int>(123);
Send< bool>(true);
But why isn't it working? And what is the right way to do it?
Overload resolution is performed at compile time. So the compiler's trying to find a method with a parameter which will be valid *whatever type T is, (within its constraints, which don't help here). It can't find such a method. Given that the only constraint is that T must be a struct, the only non-generic parameter type that would be valid would be object (via boxing).
If your aim was to use whichever overload was appropriate based on the execution-time type of the object, you'll need to either use dynamic typing, like this:
public void Send(dynamic d) {
BinaryWriter bw = new BinaryWriter(stream);
bw.Write(d);
}
... or fetch and execute the right overload with reflection (which is sort of what dynamic typing would do).

Categories

Resources