The following call will fail because compiler expects method SetAll(PropertyInfo, int)
.
var infos = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
var setters = infos.Select(SetAll); // no overload matches delegate.
private Action SetAll(PropertyInfo info, object obj) => () => info.SetValue(this, obj);
So that means compiler can't use this overload any way. it can't cast int
to object
.
Having this in mind, Why the following call is ambiguous?
var b = infos.Select(SetAll); // ambiguous between Select<PropertyInfo, int, Action>
// and Select<PropertyInfo, Action>
private Action SetAll(PropertyInfo info, object obj) => () => info.SetValue(this, obj);
private Action SetAll(PropertyInfo info) => () => info.SetValue(this, null);
If compiler can't use overload with object any way then why its struggling here?
Here is the actual code I'm having. I can deal with this problem easily but im just being curios.
var infos = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
if (useDefaultsOnReset)
{
var defaults = infos.Select(GetAll);
_resetters = infos.Zip(defaults, SetAll).ToArray();
}
else
{
_resetters = infos.Select(SetAll).ToArray(); // error
}
private object GetAll(PropertyInfo info) => info.GetValue(this);
private Action SetAll(PropertyInfo info, object obj) => () => info.SetValue(this, obj);
private Action SetAll(PropertyInfo info) => () => info.SetValue(this, null);
This is because the
System.Func<in T1, in T2, out TResult>
is contravariant in its argument types. This is denoted by thein
modifier on the corresponding type parameters. What this means is that it is a match for any function taking an argument of typeT1
or any typeT1
can be assigned to, and an argument of typeT2
or any typeT2
can be assigned to. Your first signature matches the overload ofEnumerable.Select
that does not incorporate an index. However, your second signature actually matches the overload ofEnumerable.Select
which does incorporate the index becauseint
is assignable toobject
.To demonstrate this. Simply create an arbitrary class and change your program like so.
You will observe the error disappears as
int
is not assignable toA
.As discussed in the comments, there is a wrinkle I failed to take into account. The contravariant relationship holds between reference types and between generics that are not constrained to be value types but it specifically does not work in when directly assigning between delegates taking
int
andobject
GivenThe following are both errors
However, if we replace
int
with say some classA
The first is an error because an object is not an A, but the second succeeds as explained above.