I'm a lambda newbie, so if I'm missing vital information in my description please tell me. I'll keep the example as simple as possible.
I'm going over someone else's code and they have one class inheriting from another. Here's the derived class first, along with the lambda expression I'm having trouble understanding:
class SampleViewModel : ViewModelBase
{
private ICustomerStorage storage = ModelFactory<ICustomerStorage>.Create();
public ICustomer CurrentCustomer
{
get { return (ICustomer)GetValue(CurrentCustomerProperty); }
set { SetValue(CurrentCustomerProperty, value); }
}
private int quantitySaved;
public int QuantitySaved
{
get { return quantitySaved; }
set
{
if (quantitySaved != value)
{
quantitySaved = value;
NotifyPropertyChanged(p => QuantitySaved); //where does 'p' come from?
}
}
}
public static readonly DependencyProperty CurrentCustomerProperty;
static SampleViewModel()
{
CurrentCustomerProperty = DependencyProperty.Register("CurrentCustomer", typeof(ICustomer),
typeof(SampleViewModel), new UIPropertyMetadata(ModelFactory<ICustomer>.Create()));
}
//more method definitions follow..
Note the call to NotifyPropertyChanged(p => QuantitySaved) bit above. I don't understand where the "p" is coming from.
Here's the base class:
public abstract class ViewModelBase : DependencyObject, INotifyPropertyChanged, IXtremeMvvmViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged<T>(Expression<Func<ViewModelBase, T>> property)
{
MvvmHelper.NotifyPropertyChanged(property, PropertyChanged);
}
}
There's a lot in there that's not germane to the question I'm sure, but I wanted to err on the side of inclusiveness.
The problem is, I don't understand where the 'p' parameter is coming from, and how the compiler knows to (evidently?) fill in a type value of ViewModelBase from thin air?
For fun I changed the code from 'p' to 'this', since SampleViewModel inherits from ViewModelBase, but I was met with a series of compiler errors, the first one of which statedInvalid expression term '=>' This confused me a bit since I thought that would work.
Can anyone explain what's happening here?
where does 'p' come from in
NotifyPropertyChanged(p => QuantitySaved);
The lambda is being passed to a method called NotifyPropertyChanged. There is one overload of that method. It has formal parameter type Expression<Func<ViewModelBase, T>>. That is, the formal parameter expects to get a lambda that takes a ViewModelBase and returns a T, for some T.
The p is the parameter that the lambda takes.
The compiler is able to infer that the author of the code neglected to spell out the type of the lambda parameter explicitly. The author could also have written:
NotifyPropertyChanged((ViewModelBase p) => QuantitySaved);
had they wanted to be explicit about it.
how does the compiler know to fill in a type value of ViewModelBase from thin air?
The compiler examines all possible overloads of NotifyPropertyChanged that could possibly take a lambda in that argument position. It infers the formal parameter type of the lambda from the delegate types that are in the formal parameter types of the NotifyPropertyChanged methods. An example might help. Suppose we have:
void M(Func<int, double> f) {}
void M(Func<string, int> f) {}
and a call
M(x=>x.Length);
The compiler must infer the type of the lambda parameter x. What are the possibilities? There are two overloads of M. Both take a delegate in the formal parameter of M corresponding to the first argument passed in the call. In the first one, the function is from int to double, so x could be of type int. In the second one, the formal parameter of M is a function from string to int, so x could be string.
The compiler must now determine which one is correct. In order for the first one to be correct, the body of the lambda must return a double. But if x is int, there is no property Length on x that returns a double. So x cannot be int. Can x be string? Yes. There is a property Length on x that returns an int if x is string.
Therefore the compiler deduces that x is string.
These deductions can get extraoridinarily complicated. A slightly more complicated example:
void M<A, B, C>(A a1, Func<List<A>, B> a2, Func<B, C> a3) {}
...
M(123, x=>x.Count.ToString(), y=>y.Length);
Type inference must infer the types A, B, C and therefore the types of x and y. The compiler first infers that A must be int since a1 is 123. It then infers that x must be List<int> from that fact. It then infers that B must be string, and therefore y is string, and therefore C is the type of y.Length, which is int.
It gets a lot more complicated from there, believe me.
If this subject interests you, I have written a number of articles and filmed some videos on the subject of various kinds of type inference performed by the compiler. See
http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/
for all the details.
For fun I changed the code from 'p' to 'this', since SampleViewModel inherits from ViewModelBase, but I was met with a series of compiler errors, the first one of which statedInvalid expression term '=>' This confused me a bit since I thought that would work.
The only acceptable left-hand-side of a lambda operator is a lambda parameter list; "this" is never a legal lambda parameter list. The compiler is expecting "this" to be followed by ".SomeMethod()" or some such thing; the compiler assumes that "this" will never be followed by "=>". When you violate that assumption, bad things happen.
p is just a dummy name, it's the name of the parameter like in any method. You could name it x or Fred, if you like.
Remember, lambda expressions are just very, very special anonymous methods.
In regular methods you have parameters, and they have names:
public double GetQuantitysaved(ViewModelBase p) {
return QuantitySaved;
}
In anonymous methods you have parameters, and they have names:
delegate(ViewModelBase p) { return QuantitySaved; }
In lambda expressions you have parameters, and they have names:
p => QuantitySaved
The p here plays the same role in all three versions. You can name it whatever you want. It's just the name of a parameter to the method.
In the last case, the compiler does a lot of work to figure out that p represents a parameter of type ViewModelBase so that p => QuantitySaved can play the role of
Expression<Func<ViewModelBase, T>> property
For fun I changed the code from p to this, since SampleViewModel inherits from ViewModelBase, but I was met with a series of compiler errors, the first one of which stated Invalid expression term '=>' This confused me a bit since I thought that would work.
Well, this is not a valid parameter name because it's a reserved keyword. It's best to think of p => QuantitySaved as
delegate(ViewModelBase p) { return QuantitySaved; }
until you get comfortable with the idea. In this case, this could never be substituted in for p as it is not a valid parameter name.
The lambda p => QuantitySaved is an expression of type Expression<Func<ViewModelBase, int>>. Since the method NotifyPropertyChanged is looking for an expression of <ViewModelBase, T>, it fits.
So the compiler is able to infer that p is a ViewModelBase. p didn't "come from" anywhere, it's basically being declared right here. It's a parameter for the lambda. It's going to be filled in when someone uses the property parameter of your method. For example, if you put your lambda into a separate variable called lambda, you could call it with lambda(this) and it would return the QuantitySaved value.
The reason you can't use this in the lambda is because it's expecting a parameter name, and this isn't a valid name. The point is that you could call it on any instance of ViewModelBase, not just the one that created the lambda.
The easy way to understand this is to replace this:
p => QuantitySaved // lambda
with this:
delegate (ViewModelBase p) { return QuantitySaved; } // anonymous delegate
Which is effectively the same. p is a parameter name for first parameter of your anonymous delegate. You can give it any name appropriate for parameter names (this is a keyword, you cannot use it as parameter name)
In this particular example this p variable is redundant by the way, you could use parameterless delegate as well.
From the NotifyPropertyChanged signature:
void NotifyPropertyChanged<T>(Expression<Func<ViewModelBase, T>> property)
The method expects an expression that takes an input of type ViewModelBase and returns an instance of type T.
The p parameter is an instance of ViewModelBase.
Related
I don't understand this case:
public delegate int test(int i);
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
public test Fail()
{
Func<int, int> f = x => x;
return f; // <- code doesn't compile
}
Why is compilation OK when I use Invoke method and not OK when I return csharp Func<int,int> directly?
There are two things you need to know to understand this behaviour.
All delegates derive from System.Delegate, but different delegates have different types and therefore cannot be assigned to each other.
The C# language provides special handling for assigning a method or lambda to a delegate.
Because different delegates have different types, that means you can't assign a delegate of one type to another.
For example, given:
delegate void test1(int i);
delegate void test2(int i);
Then:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
The first line above compiles OK because it is using the special handling for assigning a lambda or a method to a delegate.
In fact, this line is effectively rewritten like this by the compiler:
test1 a = new test1(Console.WriteLine);
The second line above does not compile because it is trying to assign an instance of one type to another incompatible type.
As far at the types go, there is no compatible assignment between test1 and test2 because they are different types.
If it helps to think about it, consider this class hierarchy:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
The following code will NOT compile, even though Test1 and Test2 derive from the same base class:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
This explains why you can't assign one delegate type to another. That's just the normal C# language.
However, the crucial thing is to understand why you're allowed to assign a method or lambda to a compatible delegate. As noted above, this is part of the C# language support for delegates.
So finally to answer your question:
When you use Invoke() you are assigning a METHOD call to the delegate using the special C# language handling for assigning methods or lambdas to a delegate rather than trying to assign an incompatible type - hence it compiles OK.
To be completely clear, the code which compiles in your OP:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Is actually converted conceptually to something like:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Whereas the failing code is attempting to assign between two incompatible types:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}
In the second case, f is of type Func<int, int>, but the method is said to return a test. These are unrelated (delegate) types, that are unconvertible to each other, so a compiler error occurs. You can go to this section of the language spec, and search for "delegate". You will find no mention of conversions between delegates that have the same signatures.
In the first case however, f.Invoke is a method group expression, which doesn't actually have a type. The C# compiler will convert method group expressions to specific delegate types according to the context, through a method group conversion.
(Quoting the 5th bullet here, emphasis mine)
An expression is classified as one of the following:
...
A method group, which is a set of overloaded methods resulting from a member lookup. [...] A method group is permitted in an invocation_expression, a delegate_creation_expression and as the left hand side of an is operator, and can be implicitly converted to a compatible delegate type.
In this case, it is converted to the test delegate type.
In other words, return f doesn't work because f already has a type, but f.Invoke doesn't have a type yet.
Issue out here is Type compatibility:
Following is the definition of Func delegate from MSDN Sources:
public delegate TResult Func<in T, out TResult>(T arg);
If you see there's no direct relation between the Func mentioned above and your defined Delegate:
public delegate int test(int i);
Why 1st snippet compiles:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Delegates are compared using signature, which is input parameters and Output result, ultimately a Delegate is a Function pointer and two functions can be compared only via signature. At runtime the method invoked via Func is assigned to the Test delegate, since Signature is same it works seamlessly. It's a function pointer assignment, where Test delegate will now invoke the method pointed by the Func delegate
Why 2nd Snippet fails to compile
Between Func and test delegate, there's no type / assignment compatibility, Func cannot fill in as part of the Type system rules. Even when its result can be assigned and filled in test delegate as done in the first case.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm currently working on a project, and need a method to get me a variable's name. (XmlNode type). I found this solution - but I have no clue how it works. Any explanation would be helpful. Thank you!
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
In particular, I don't understand why the parameter is (new {var1}) and (() => var1) when calling the methods, what <T>(T item) where T : class means, and what <T>(Expression<Func<T>> expr) means.
I did read about the lambda operation and <T>, but that doesn't really help that much.
First, the nameof operator was introduced in, I believe, c# 6. It can do what you want. You use it like this:
var myVariable = new Object();
var myVariableName = nameof(myVariable);
Now to unpack your question.
What is (new {var1})?
Here you are calling the GetName method. That method takes a single parameter. The object being passed to the method in this case is instantiated with this code: new { var1 }. Here new { var1 } is creating an anonymous type. The object being created has a single property named 'var1' whose value is the variable var1. Because a property name was not supplied the property was automatically given the same name as the variable. You could have explicitly named the property when you declared the anonymous type like this: new { var1 = var1 }. Or you could have given your property a completely different name: new { DifferentName = var1 } (but this would cause GetName to return the wrong result - see below). If you were to explicitly define these types as classes they would look something like these, respectively:
public class MyClass<T>
{
public MyClass(T property)
{
var1 = property;
}
public var1 { get; }
}
and this:
public class MyClass<T>
{
public MyClass(T property)
{
DifferentName = property;
}
public DifferentName { get; }
}
What is <T>(T item) where T : class?
The <T> in GetName<T> or GetName2<T> is a generic type parameter (generics). In this case it allows you to delay the type specification of the method parameter until the method is invoked. So if I had a method with this signature, for example, MyMethod<T>(T item) I could later call it with an int like this MyMethod<int>(2) or a string like this MyMethod<string>('some string'). Here I am explicitly specifying the type with <int> and <string>. In many cases, when the type is unambigous, you can exclude the type declaration and C# will infer it. So I could do this MyMethod('some string') and C# will be able to infer the type is string. That is what is happening here: GetName(new { var1 }). Since new { var1 } is an anonymous type there is no way to explicitly specify the type when calling GetName. But you can still call GetName with an anonymous type simply by allowing C# to infer the type.
The where T : class portion of the method signature is just a generic constraint, i.e. a constraint is being placed on the types that can be passed to this method. In this case the constraint is that T must be a class and not a value type.
How does GetName<T> work?
This function is using reflection to inspect the object that was passed to it. Here is what is going on: typeof(T) gets the type of object that was passed (remember we are passing an anonymous type), GetProperties() gets all the properties of the type - this will give you an array of PropertyInfo, [0] gives you the first property in that array (in the case where new { var1 } is passed to this method the object will only have a single property named 'var1'), and finally Name gives you the name of that property.
This method is making assumptions about the object being passed to it. Specifically that the object passed has at least 1 property and that the name of the the first property has the same name as the variable whose name we are interested in. This method is far from foolproof, it could easily be broken at runtime by passing an object with no properties, or you could get back the wrong name if you failed to pass an object that conformed to the assumptions that GetName is making.
Interestingly, GetName could have been implemented without generics like this:
static string GetName3(object item)
{
return item.GetType().GetProperties()[0].Name;
}
Perhaps the author was attempting to take advantage of at least a tiny bit of compile time checking by eliminating an entire class of objects (value types) that have no properties from being passed to the method.
What is (() => var1)?
This is an expression. This particular expression represents a function that takes no parameters () and returns an object. I know that from the method signature of GetName2:
GetName2<T>(Expression<Func<T>> expr)`
See, the expr parameter is an Expression of type Func (a function) that takes no parameters and returns a on object of type T.
How does GetName2<T>(Expression<Func<T>> expr) work?
Well... the short and probably not very accurate answer is that it is returning the right side of the expression. So you pass in () => var1 and you get back var1. Let's just leave it at that for now.
new {var1} creates an anonymous object
(() => var1) is a lambda function with no parameters shorthand for:
delegate void () { return var1;}
<T>(T item) where T : class is reflection and constraining the generic
parameter to a class. See DarkSquirrel42 answer
As an example, let's use something like a calculator with elements of various types, functions that evaluate for different element types, and a context to store elements and run functions. The interfaces are something like this:
public interface IElement {
}
public interface IChildElement : IElement {
double Score { get; }
}
public interface IGrandchildElement : IChildElement {
int Rank { get; }
}
public interface IFunction<Tout, in Tin> where Tin : IElement {
Tout Evaluate(Tin x, Tin y);
}
public interface IContext<Tin> where Tin : IElement {
Tout Evaluate<Tout>(string x, string y, IFunction<Tout, Tin> eval);
}
Note that functions may return arbitrary types. A dummy implementation is as follows, where I have a function called Foo that can be used for both IChildElement and IGrandchildElement, and returns double in both cases:
public class ChildElement : IChildElement {
public double Score { get; internal set; }
}
public class GrandchildElement : ChildElement, IGrandchildElement {
public int Rank { get; internal set; }
}
public class Foo : IFunction<double, IChildElement>, IFunction<double, IGrandchildElement> {
public double Evaluate(IChildElement x, IChildElement y) {
return x.Score / y.Score;
}
public double Evaluate(IGrandchildElement x, IGrandchildElement y) {
return x.Score * x.Rank / y.Score / y.Rank;
}
}
public class Context<T> : IContext<T> where T : IElement {
protected Dictionary<string, T> Results { get; set; }
public Context() {
this.Results = new Dictionary<string, T>();
}
public void AddElement(string key, T e) {
this.Results[key] = e;
}
public Tout Evaluate<Tout>(string x, string y, IFunction<Tout, T> eval) {
return eval.Evaluate(this.Results[x], this.Results[y]);
}
}
Some sample execution:
Context<IChildElement> cont = new Context<IChildElement>();
cont.AddElement("x", new ChildElement() { Score = 1.0 });
cont.AddElement("y", new ChildElement() { Score = 2.0 });
Foo f = new Foo();
double res1 = cont.Evaluate("x", "y", f); // This does not compile
double res2 = cont.Evaluate<double>("x", "y", f); // This does
As you can see, my problem is that I seemingly need to hard-type the call to Context.Evaluate. If I don't, the compiler says it cannot infer the type of the arguments. This is particularly striking to me since in both cases the Foo function returns double.
If Foo implements only IFunction<double, IChildElement> or IFunction<double, IGrandchildElement> I don't have this problem. But it does.
I don't understand it. I mean, adding the <double> does not differentiate between IFunction<double, IGrandchildElement> and IFunction<double, IChildElement> because they both return double. For what I understand, it doesn't provide the compiler with any additional information to distinguish.
In any case, is there any way I can avoid having to hard-type all calls to Task.Evaluate? In the real world I have several functions, so being able to avoid it would be great.
Bounty for sound explanation of why adding the <double> helps the compiler. Is this a problem with the compiler being too lazy so to speak?
Old update: using delegates
An option could be to use delegates instead of IFunctions in IContext.Evaluate:
public interface IContext<Tin> where Tin : IElement {
Tout Evaluate<Tout>(string x, string y, Func<Tin, Tin, Tout> eval);
}
public class Context<T> : IContext<T> where T : IElement {
// ...
public Tout Evaluate<Tout>(string x, string y, Func<T, T, Tout> eval) {
return eval(this.Results[x], this.Results[y]);
}
}
Doing so, we don't need to hard-type <double> when calling IContext.Evaluate:
Foo f = new Foo();
double res1 = cont.Evaluate("x", "y", f.Evaluate); // This does compile now
double res2 = cont.Evaluate<double>("x", "y", f.Evaluate); // This still compiles
So here the compiler does work as expected. We avoid the need to hard-type, but I don't like the fact that we use IFunction.Evaluate instead of the IFunction object itself.
(I haven't gone through the delegates version. I figured this answer was long enough already...)
Let's start off by simplifying the code considerably. Here's a short but complete example which still demonstrates the problem, but removes everything irrelevant. I've also changed the order of the type arguments in IFunction just to match more normal conventions (e.g. Func<T, TResult>):
// We could even simplify further to only have IElement and IChildElement...
public interface IElement {}
public interface IChildElement : IElement {}
public interface IGrandchildElement : IChildElement {}
public interface IFunction<in T, TResult> where T : IElement
{
TResult Evaluate(T x);
}
public class Foo : IFunction<IChildElement, double>,
IFunction<IGrandchildElement, double>
{
public double Evaluate(IChildElement x) { return 0; }
public double Evaluate(IGrandchildElement x) { return 1; }
}
class Test
{
static TResult Evaluate<TResult>(IFunction<IChildElement, TResult> function)
{
return function.Evaluate(null);
}
static void Main()
{
Foo f = new Foo();
double res1 = Evaluate(f);
double res2 = Evaluate<double>(f);
}
}
This still has the same problem:
Test.cs(27,23): error CS0411: The type arguments for method
'Test.Evaluate<TResult>(IFunction<IChildElement,TResult>)' cannot be
inferred from the usage. Try specifying the type arguments explicitly.
Now, as for why it happens... the problem is type inference, as others have said. The type inference mechanism in C# (as of C# 3) is pretty good, but it's not as powerful as it could be.
Let's look at what happens at the method invocation part, with reference to the C# 5 language specification.
7.6.5.1 (method invocations) is the important part here. The first step is:
The set of candidate methods for the method invocation is constructed. For each method F associated with the method group M:
If F is non-generic, F is a candidate when:
M has no type argument list, and
F is applicable with respect to A (§7.5.3.1).
If F is generic and M has no type argument list, F is a candidate when:
Type inference (§7.5.2) succeeds, inferring a list of type arguments for the call, and
Once the inferred type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (§4.4.4), and the parameter list of F is applicable with respect to A (§7.5.3.1).
If F is generic and M includes a type argument list, F is a candidate when:
F has the same number of method type parameters as were supplied in the type argument list, and
Once the type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (§4.4.4), and the parameter list of F is applicable with respect to A (§7.5.3.1).
Now here, the method group M is a set with a single method (Test.Evaluate) - fortunately section 7.4 (member lookup) is simple. So we only have a single F method to consider.
It is generic, and M has no type argument list, so we end up straight in section 7.5.2 - type inference. Notice how if there is an argument list, this is skipped entirely, and the third major bullet point above is satisfied - which is why the Evaluate<double>(f) call succeeds.
So, we've got a pretty good indication by now that the problem lies in type inference. Let's dive into it. (This is where it gets tricky, I'm afraid.)
7.5.2 itself is mostly just description, including the fact that type inference happens in phases.
The generic method we're trying to call is described as:
Tr M<X1...Xn>(T1 x1 ... Tm xm)
and the method call is described as:
M(E1 ... Em)
So in our case, we have:
Tr is TResult which is the same as X1.
T1 is IFunction<IChildElement, TResult>
x1 is function, a value parameter
E1 is f, which is of type Foo
Now let's try to apply that for the rest of type inference...
7.5.2.1 The first phase
For each of the method arguments Ei:
If Ei is an anonymous function, an explicit parameter type inference (§7.5.2.7) is made from Ei to Ti
Otherwise, if Ei has a type U and xi is a value parameter then a lower-bound inference is made from U to Ti.
Otherwise, if Ei has a type U and xi is a ref or out parameter then an exact inference is made from U to Ti.
Otherwise, no inference is made for this argument.
The second bullet point is relevant here: E1 is not an anonymous function, E1 has a type Foo, and x1 is a value parameter. So we end up with a lower-bound inference from Foo to T1. That lower-bound inference is described in 7.5.2.9. The important part here is:
Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:
[...]
V is a constructed class, struct, interface or delegate type C<V1...Vk> and there is a unique type C<U1...Uk> such that U (or, if U is a type parameter, its effective base class or any member of its effective interface set) is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) C<U1...Uk>.
(The "uniqueness" restriction means that in the case interface C<T>{} class U: C<X>, C<Y>{}, then no inference is made when inferring from U to C<T> because U1 could be X or Y.)
For the purposes of this part, U is Foo, and V is IFunction<IChildElement, TResult>. However, Foo implements both IFunction<IChildElement, double> and IFunction<IGrandchildelement, double>. So even though in both cases we'd end up with U2 as double, this clause isn't satisfied.
One thing which does surprise me in this is that this doesn't rely on the T in IFunction<in T, TResult> being contravariant. We get the same issue if we remove the in part. I would have expected it to work in that case, as there wouldn't be a conversion from IFunction<IGrandchildElement, TResult> to IFunction<IChildElement, TResult>. It's possible that that part is a compiler bug, but it's more likely to be me misreading the spec. However, in the case that's actually given, that's irrelevant - because of the contravariance of T, there is such a conversion, so both interfaces really are significant.
Anyway, that means we don't actually end up with any type inference from this argument!
That's the whole of the first phase.
The second phase is described like this:
7.5.2.2 The second phase
The second phase proceeds as follows:
All unfixed type variables Xi which do not depend on (§7.5.2.5) any Xj are fixed (§7.5.2.10).
If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
There is at least one type variable Xj that depends on Xi
Xi has a non-empty set of bounds
If no such type variables exist and there are still unfixed type variables, type inference fails.
Otherwise, if no further unfixed type variables exist, type inference succeeds.
Otherwise, for all arguments Ei with corresponding parameter type Ti where the output types (§7.5.2.4) contain unfixed type variables Xj but the input types (§7.5.2.3) do not, an output type inference (§7.5.2.6) is made from Ei to Ti. Then the second phase is repeated.
I'm not going to copy out all the sub-clauses, but in our case...
Type variable X1 doesn't depend on any other type variables, as there aren't any other type variables. So we need to fix X1. (The section reference here is wrong - it should actually be 7.5.2.11. I'll let Mads know.)
We have no bounds for X1 (because the lower-bound inference earlier on didn't help) so we end up failing type inference at this point. Bang. It all hinges around that uniqueness part in 7.5.2.9.
Of course, this could be fixed. The type inference part of the specification could be made more powerful - the trouble is that that would also make it more complicated, resulting in:
It being harder for developers to reason about type inference (it's hard enough as it is!)
It being harder to specify correctly with no gaps
It being harder to implement correctly
Quite possibly, it having worse performance at compile-time (which can be an issue in interactive editors such as Visual Studio, which need to perform the same type inference for things like Intellisense to work)
It's all a balancing act. I think the C# team have done pretty well - the fact that it doesn't work in corner cases such as this isn't too much of a problem, IMO.
Type inference fails because the compiler is not able to fix the type parameter to a unique mapping.
There is an ambiguity between IFunction<double, IChildElement> and IFunction<double, IGrandChildElement> because they are both bindable.
When type inference fail you must explicitly specify your type arguments. This is as per the C# language specification.
By specifying the explicit type argument you help the compiler since it can skip type inference altogether.
After you have explicitly specified that T is bound to double there is no longer an ambiguity since Tin is bound to IChildElement via your declaration of Context<IChildElement> and Tout is bound to double via the explicit type argument.
I agree that you may argue that the compiler might as well have inferred that usage since the type argument in this case doesn't really provide any additional information.
However, the specification says:
Type inference occurs as part of the binding-time processing of a
method invocation (§7.6.5.1) and takes place before the overload
resolution step of the invocation
...so I guess they wanted to separate these things. The reason for that is beyond me. I'm guessing it could have been simplicity of the specification or support for future extensions, or just that they didn't think of it :-)
The reason this is happening is because Foo() implements IFunction for both IChildElement and IGrandchildElement. Since your usage is of the type IChildElement, it could be referring to either IChildElement or IGrandchildElement so the call is ambiguous since IFunction<double, IGrandchildElement> is a IFunction<double, IChildElement>. Note that the problem is not being caused because of IChildElement and IGrandchildElement, but because it implements two potential IFunction types, it does not even consider the return type double.
// f is both an IFunction<double, IGrandchildElement>
// and an IFunction<double, IChildElement>
Foo f = new Foo();
double res1 = cont.Evaluate("x", "y", f); // This does not compile
double res2 = cont.Evaluate<double>("x", "y", f); // This does
So you need to make it more specific somehow, there are two ways of doing this using casts:
double res3 = cont.Evaluate<double>("x", "y", f);
double res4 = cont.Evaluate("x", "y", (IFunction<double, IChildElement>)f);
You don't want to be doing this every time as you've said but the last line's method of casting reveals a potential solution to your problem; casting Foo to the desired interface into a variable and using that variable when calling cont.Evaluate().
IFunction<double, IChildElement> iFunc = f;
double res5 = cont.Evaluate("x", "y", iFunc);
I know that what I'm doing can be done in a different way, but I'm curious about how things work. The following is a simplified code which doesn't compile, but it supposed to show my goal.
private void Execute()
{
GeneralizedFunction("1", "2", i => Transform(i));
}
void GeneralizedFunction(string aStringA, string aStringB, Func<string, T> aAction)
{
A result1 = aAction(aStringA);
B result2 = aAction(aStringB);
// Do something with A and B here
}
T Transform<T>(string aString)
{
return default(T);
}
Transform is a generic convertion from string to some object (think deserialization).
GeneralizedFunction uses two specializations of transform: one for type A and one for type B. I know I can do this in a number of other ways (say by introducing a parameter for the type of the object), but I'm looking for explanations of whether it is possible or impossible to do this with generics/lambdas. If Transform is specialized before it is passed as a parameter to GeneralizedFunction, then it's impossible. Then the question is why this possibility is restricted.
This answer doesn't explain the reason why, just how to work around the limitation.
Instead of passing an actual function, you can pass an object that has such a function:
interface IGenericFunc
{
TResult Call<TArg,TResult>(TArg arg);
}
// ... in some class:
void Test(IGenericFunc genericFunc)
{
// for example's sake only:
int x = genericFunc.Call<String, int>("string");
object y = genericFunc.Call<double, object>(2.3);
}
For your specific use case, it can be simplified to:
interface IDeserializerFunc
{
T Call<T>(string arg);
}
// ... in some class:
void Test(IDeserializerFunc deserializer)
{
int x = deserializer.Call<int>("3");
double y = deserializer.Call<double>("3.2");
}
What you're asking to do isn't possible using generics alone. The compiler needs to generate two typed versions of your Transform function: one to return type A and one for type B. The compiler has no way of knowing to generate this at compile time; only by running the code would it know that A and B are required.
One way to solve it would be to pass in the two versions:
private void Execute()
{
GeneralizedFunction("1", "2", i => Transform<A>(i), i => Transform<B>(i));
}
void GeneralizedFunction(string aStringA, string aStringB, Func<string, A> aAction, Func<string, B> bAction)
{
A result1 = aAction(aStringA);
B result2 = bAction(aStringB);
}
The compiler knows exactly what it needs to generate in this case.
Try the following signature:
void GeneralizedFunction<T>(string aStringA, string aStringB, Func<string, T> aAction)
(Note that GeneralizedFunction has to be generic; the compiler will automatically guess the type parameter when calling the method).
It seems the answer is "no".
When you call Transform directly, you have to specify a type parameter:
int i = Transform<int>("");
So hypothetically, if you could pass an incompletely-constructed generic function like you want to, you'd need to specify the type parameters as well:
void GeneralizedFunction(string aStringA, string aStringB, Func<string, T> aAction)
{
A result1 = aAction<A>(aStringA);
B result2 = aAction<B>(aStringB);
// Do something with A and B here
}
So it seems to me that you could hypothetically do this, if C# had a syntax like that.
But what's the use case? Aside from transforming strings to the default value of an arbitrary type, I don't see much use for this. How could you define a function that would provide a meaningful result in either of two different types using the same series of statements?
EDIT
An analysis of why it's not possible:
When you use a lambda expression in your code, it is compiled into either a delegate or an expression tree; in this case, it's a delegate. You can't have an instance of an "open" generic type; in other words, to create an object from a generic type, all type parameters must be specified. In other words, there's no way to have an instance of a delegate without providing arguments for all of its type parameters.
One of the C# compiler's helpful features is implicit method group conversions, where the name of a method (a "method group") can be implicitly converted to a delegate type representing one of the overloads of that method. Similarly, the compiler implicitly converts a lambda expression to a delegate type. In both cases, the compiler emits code to create an instance of the delegate type (in this case, to pass it to the function). But the instance of that delegate type still needs to have a type argument for each of its type parameters.
To pass the generic function as a generic function, it seems, the compiler would need to be able to pass the method group or the lambda expression to the method without conversion, so the aAction parameter would somehow have a type of "method group" or "lambda expression." Then, the implicit conversion to a delegate type could happen at the call sites A result1 = aAction<A>(aStringA); and B result2 = aAction<B>(aStringB);. Of course, at this point, we are well into the universe of contrafactuals and hypotheticals.
The solution I came up with over lunch was this, assuming a function Deserialize<T> that takes a string containing serialized data and returns an object of type T:
void GeneralizedFunction<T>(string aStringA, string aStringB, Func<T, string> stringGetter)
{
A result1 = Deserialize<A>(stringGetter(aStringA));
B result2 = Deserialize<B>(stringGetter(aStringB));
}
void Example(string serializedA, string serializedB, string pathToA, string pathToB, FileInfo a, FileInfo b)
{
GeneralizedFunction(serializedA, serializedB, s => s);
GeneralizedFunction(pathToA, pathToB, File.ReadAllText);
GeneralizedFunction(a, b, fi => File.ReadAllText(fi.FullName));
}
void GeneralizedFunction<T>(string aStringA, string aStringB, Func<string, T> aAction)
{
A result1 = aAction(aStringA);
B result2 = aAction(aStringB);
}
T Transform<T>(string aString)
{
return default(T);
}
What does the statement mean?
From here
ref and out parameters in C# and
cannot be marked as variant.
1) Does it mean that the following can not be done.
public class SomeClass<R, A>: IVariant<R, A>
{
public virtual R DoSomething( ref A args )
{
return null;
}
}
2) Or does it mean I cannot have the following.
public delegate R Reader<out R, in A>(A arg, string s);
public static void AssignReadFromPeonMethodToDelegate(ref Reader<object, Peon> pReader)
{
pReader = ReadFromPeon;
}
static object ReadFromPeon(Peon p, string propertyName)
{
return p.GetType().GetField(propertyName).GetValue(p);
}
static Reader<object, Peon> pReader;
static void Main(string[] args)
{
AssignReadFromPeonMethodToDelegate(ref pReader);
bCanReadWrite = (bool)pReader(peon, "CanReadWrite");
Console.WriteLine("Press any key to quit...");
Console.ReadKey();
}
I tried (2) and it worked.
"out" means, roughly speaking, "only appears in output positions".
"in" means, roughly speaking, "only appears in input positions".
The real story is a bit more complicated than that, but the keywords were chosen because most of the time this is the case.
Consider a method of an interface or the method represented by a delegate:
delegate void Foo</*???*/ T>(ref T item);
Does T appear in an input position? Yes. The caller can pass a value of T in via item; the callee Foo can read that. Therefore T cannot be marked "out".
Does T appear in an output position? Yes. The callee can write a new value to item, which the caller can then read. Therefore T cannot be marked "in".
Therefore if T appears in a "ref" formal parameter, T cannot be marked as either in or out.
Let's look at some real examples of how things go wrong. Suppose this were legal:
delegate void X<out T>(ref T item);
...
X<Dog> x1 = (ref Dog d)=>{ d.Bark(); }
X<Animal> x2 = x1; // covariant;
Animal a = new Cat();
x2(ref a);
Well dog my cats, we just made a cat bark. "out" cannot be legal.
What about "in"?
delegate void X<in T>(ref T item);
...
X<Animal> x1 = (ref Animal a)=>{ a = new Cat(); }
X<Dog> x2 = x1; // contravariant;
Dog d = new Dog();
x2(ref d);
And we just put a cat in a variable that can only hold dogs. T cannot be marked "in" either.
What about an out parameter?
delegate void Foo</*???*/T>(out T item);
? Now T only appears in an output position. Should it be legal to make T marked as "out"?
Unfortunately no. "out" actually is not different than "ref" behind the scenes. The only difference between "out" and "ref" is that the compiler forbids reading from an out parameter before it is assigned by the callee, and that the compiler requires assignment before the callee returns normally. Someone who wrote an implementation of this interface in a .NET language other than C# would be able to read from the item before it was initialized, and therefore it could be used as an input. We therefore forbid marking T as "out" in this case. That's regrettable, but nothing we can do about it; we have to obey the type safety rules of the CLR.
Furthermore, the rule of "out" parameters is that they cannot be used for input before they are written to. There is no rule that they cannot be used for input after they are written to. Suppose we allowed
delegate void X<out T>(out T item);
class C
{
Animal a;
void M()
{
X<Dog> x1 = (out Dog d) =>
{
d = null;
N();
if (d != null)
d.Bark();
};
x<Animal> x2 = x1; // Suppose this were legal covariance.
x2(out this.a);
}
void N()
{
if (this.a == null)
this.a = new Cat();
}
}
Once more we have made a cat bark. We cannot allow T to be "out".
It is very foolish to use out parameters for input in this way, but legal.
UPDATE: C# 7 has added in as a formal parameter declaration, which means that we now have both in and out meaning two things; this is going to create some confusion. Let me clear that up:
in, out and ref on a formal parameter declaration in a parameter list means "this parameter is an alias to a variable supplied by the caller".
ref means "the callee may read or write the aliased variable, and it must be known to be assigned before the call.
out means "the callee must write the aliased variable via the alias before it returns normally". It also means that the callee must not read the aliased variable via the alias before it writes it, because the variable might not be definitely assigned.
in means "the callee may read the aliased variable but does not write to it via the alias". The purpose of in is to solve a rare performance problem, whereby a large struct must be passed "by value" but it is expensive to do so. As an implementation detail, in parameters are typically passed via a pointer-sized value, which is faster than copying by value, but slower on the dereference.
From the CLR's perspective, in, out and ref are all the same thing; the rules about who reads and writes what variables at what times, the CLR does not know or care.
Since it is the CLR that enforces rules about variance, rules that apply to ref also apply to in and out parameters.
In contrast, in and out on type parameter declarations mean "this type parameter must not be used in a covariant manner" and "this type parameter must not be used in a contravariant manner", respectively.
As noted above, we chose in and out for those modifiers because if we see IFoo<in T, out U> then T is used in "input" positions and U is used in "output" positions. Though that is not strictly true, it is true enough in the 99.9% use case that it is a helpful mnemonic.
It is unfortunate that interface IFoo<in T, out U> { void Foo(in T t, out U u); } is illegal because it looks like it ought to work. It cannot work because from the CLR verifier's perspective, those are both ref parameters and therefore read-write.
This is just one of those weird, unintended situations where two features that logically ought to work together do not work well together for implementation detail reasons.
Eric Lippert has a great explanation of why this constraint exists.
If you are looking to work around this limitation. You can do it like this:
public static class ResultExtension{
public static bool TryGetValue<T>(this IResult<T> self, out T res) {
if (self.HasValue) {
res = self.Value;
return true;
}
res = default;
return false;
}
}
public interface IResult<out T>
{
bool HasValue { get; }
T Value { get; }
}
This works because there are two structures. One structure gets the covariance and the other gets the out parameter. The out parameter is not marked as variant so the compiler is happy.
It means you can't have the following declaration:
public delegate R MyDelegate<out R, in A>(ref A arg);
Edit: #Eric Lippert corrected me that this one is still legal:
public delegate void MyDelegate<R, in A>(A arg, out R s);
It actually makes sense, since the R generic parameter is not marked as a variant, so it doesn't violate the rule. However, this one is still illegal:
public delegate void MyDelegate<out R, in A>(A arg, out R s);
But, the following code can be compiled:
interface IFoo<out T>
{
T Get();
//bool TryGet(out T value); // doesn't work: Invalid variance: The type parameter 'T' must be invariantly valid on 'IFoo<T>.TryGet(out T)'. 'T' is covariant.
bool TryGet(Action<T> value); // works!
}