I am looking at the C# 5 in a Nutshell text, section on Delegate Parameter Compatibility. It says
When you call a method, you can supply arguments that have more specific types than the parameters of that method. This is ordinary polymorphic behavior. For exactly the same reason, a delegate can have more specific parameter types than its method target. This is called contravariance.
This paragraph makes sense up until the last sentense. Why is it contravariance, i.e. what projection here is contravariant?
The accompanying example is below.
delegate void StringAction (string s);
class Test
{
static void Main()
{
StringAction sa = new StringAction (ActOnObject);
sa ("hello");
}
static void ActOnObject (object o)
{
Console.WriteLine (o); // hello
}
}
The projection of object (the parameter of the function ActionObject) to the type declared for the delegate (string) is contravariant.
This is allowed because by passing it a string (which you must due to the delegate signature), you are guaranteed that you will have an object (which the assigned function takes), so everything is nice and safe.
Just so you know, "ordinary polymorphism" in this context is actually called covariance.
See MSDN for more details.
Function types are contravariant in argument types. In your example the type
delegate void ObjectAction(object o);
is a subtype of
delegate void StringAction(string s);
since ObjectAction can be used everywhere that StringAction is used because, if a caller is passing in a string argument, the argument must also be of type object.
object is a supertype of string but ObjectAction is a subtype of StringAction; the subtyping goes in the opposite direction. This is why it's called contravariant. Because the variation in the function subtypes goes in the opposite direction of the parameter subtypes.
Related
Why is the generic method called when both overloads would match?
public static void method1(object obj)
{
Console.WriteLine("Object");
}
public static void method1<T>(T t)
{
Console.WriteLine("Type T");
}
public static void Main(String args[])
{
method1("xyz"); //Will print "Type T";
}
There should not be any conflicts here, right?
Overloads are resolved by choosing the most specific overload. In this case, method1<string>(string) is more specific than method1(object) so that is the overload chosen.
There are details in section 7.4.2 of the C# specification.
If you want to select a specific overload, you can do so by explicitly casting the parameters to the types that you want. The following will call the method1(object) overload instead of the generic one:
method1((object)"xyz");
There are cases where the compiler won't know which overload to select, for example:
void method2(string x, object y);
void method2(object x, string y);
method2("xyz", "abc");
In this case the compiler doesn't know which overload to pick, because neither overload is clearly better than the other (it doesn't know which string to implicitly downcast to object). So it will emit a compiler error.
C# will always choose the most specific method it can.
When compiling
method1("xyz");
it will look for all methods with the specified name and then attempt to match parameters. The compiler will choose the method that is the most specific, in this case it would prefer
method1(string s)
over
method1<T>(T t) with T = string
and lastly
method1(object o)
Please note #Erik's excellent answer for an example where the compiler fails to decide.
Because you are already passing in T as a parameter so you don't need to type out method1<string>("xyz");you can just go method1("xyz");, .Net already knows it's a string. If you had method1 then it would be a different story.
Also since method1(object obj) doesn't take in a string as parameter it will favor the generic function first where it can infer T. If you were to change method1(object obj) to method1(string obj) it would favor it first then the generic.
How method overloading works
To find the matching signature of a method for a call, the compiler search in the type hierarchy from bottom to top as well in virtual table:
First in the class hierarchy,
Then in the interface hierarchy.
Because classes prevail on interfaces.
Indeed, before being of type of an interface, an object is of type of a class first of all.
And non generic signatures prevail over generic as reality and facts prevail over abstraction, unless using the generic parameter allow a call on the more specialized type of instance.
Applying the theory to the question
This call:
method1("xyz");
Match perfectly with:
void method1<T>(T t) { }
Before matching with:
void method1(object obj)
Because string is a specialized object and it can be used as a generic parameter to be more acurate.
On the other side, if you write:
void method1(string obj) { }
void method1<T>(T t) { }
The first method is so called.
Case study
var instance = new List<string>();
MyMethod(instance);
MyMethod((IEnumerable<string>) instance);
MyMethod<string>(instance);
MyMethod((object)instance);
void MyMethod<T>(List<T> instance) { }
void MyMethod<T>(IEnumerable<T> list) { }
void MyMethod<T>(T instance) { }
void MyMethod(object instance) { }
The first call calls the first method because instance is type of List (type matching).
The second call calls the second method because of the side cast (implementation).
The third call calls the third method because of the generic parameter specified to act on (templating).
The fourth call calls the fourth method because of the down cast (polymorphism).
I'm using a method with this as the 1st parameter:
Action<IFieldsetter<Contact>>
How do I read this? Does is mean that this must be an Action object where the Action constructor is constrained to accept only something that implements IFieldsetter? And it looks like IFieldsetter itself is being constrained, but I don't understand this part at all.
It's not an actual constraint, but just the type it needs. So, that method's first parameter is an Action (i.e. delegate), which has only one parameter, and that parameter is a IFieldsetter<Contact>, whatever that means. My guess is that IFieldsetter exposes a setter and in this case it must handle the type Contact, but you should be the one who knows for real what they are and do! Post the code of this interface and this class if you need further help.
For example, if it was Action<IEnumerable<String>>, it would mean that the delegate receives a list of strings as a parameter. Here's some code:
// Your method with the *special* parameter.
private void ChrisMethod(Action<IEnumerable<String>> method)
{
string[] exampleList = { "First", "Second", "Third" };
method(exampleList);
}
// The method that can be used as parameter.
private void ParameterMethod(IEnumerable<String> list)
{
foreach(string str in list)
Console.WriteLine(str);
}
public void Main()
{
ChrisMethod(ParameterMethod);
}
A constraint on a type parameter is a different thing. You can learn more about that here.
A C# System.Action (MSDN) is a delegate object where Action<T> is the equivalent of a delegate function matching void FunctionName(T). So you can set it to a function and later on call that function.
The section generics block <Contact> applies to the IFieldsetter, so you have an Action that takes an argument of IFieldsetter<Contact>. Without knowing anything about the IFieldsetter I can't tell you what it's going to do with the Contact generic argument there.
In order to use this, you'll can have something resembling the following:
void Main()
{
FunctionThatDoesStuff(SetField);
}
void FunctionThatDoesStuff(Action<IFieldsetter<Contact>> action)
{
var setter = new IFieldsetter<Contact>();
action(setter);
}
void SetField(IFieldsetter<Contact> setter)
{
}
This is nested generic type parameter. From the outermost layer, you can see that this is an Action<T> delegate. And the delegate needs an argument of type T. In this case, T is replaced by IFieldsetter<Contact>. i.e. Action<IFieldSetter<Contact>> needs an argument of type IFieldSetter<Contact>. Now the IFieldSetter<T> interface sets a field of type T. And in this case, T is replaced by Contact so IFieldSetter<Contact> sets a field of type Contact.
Let's sum up: Action<IFieldsetter<Contact>> represents an Action delegate that needs an argument of type IFieldSetter which can set a field of type Contact. Now do you understand?
Action<IFieldsetter<Contact>> means Action delegate accepts a parameter of type that implements a generic interface IFieldsetter. suppose a class is implemented with IFieldsetter intercae with Contact as the generic parameter as shown below.
public class Test: IFieldsetter<Conatct>
{
}
Now instance of this test class can be passed as parameter to the Action deletegate.
How does the Action delegate with custom classes work when i am not explicitly passing the input parameter type of the referenced method :
DirectMethodCall.PassMethod(x=>x.NoReturnOneParameterMethod(1));
public static void PassMethod(Action<NewClass> c)
{
NewClass op = new NewClass();
c(op);
}
Why do i need to pass the "op" to the Action delegate ?
As comments are a bit messy to post code examples, I'll continue here.
You are not repeating code, you're misunderstanding what you've actually coded. public static void PassMethod(Action<NewClass> c) means
PassMethod requires, as a parameter, a method which executes on a NewClass object.
Maybe this makes it more clear:
void Main()
{
//I am defining the implementation of a method which requires as integer as a parameter, but I don't actually invoke it, just define it.
ExecuteMethod(i => Console.WriteLine(i));
}
public static void ExecuteMethod(Action<int> method)
{
//I don't know what method does, all I know is that I am running it with the number 5.
method(5);
}
ExecuteMethod Takes a method which requires an integer. It doesn't know what the method does. All it knows is that it requires an int, and it passes it the value 5
The actual code is from the caller:
i => Console.WriteLine(i)
Here, i is set to 5, and so the result is 5 being printed to the console.
Your PassMethod is expecting a delegate which accepts one parameter of type NewClass and it calls NoReturnOneParameterMethod() with parameter 1 and has a return type of void
Action<T> means it is a delegate that takes type T as its argument and has return type of void.
See: MSDN Action
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!
}
Why does this not work? Do I not understand delegate covariance correctly?
public delegate void MyDelegate(object obj)
public class MyClass
{
public MyClass()
{
//Error: Expected method with 'void MyDelegate(object)' signature
_delegate = MyMethod;
}
private MyDelegate _delegate;
public void MyMethod(SomeObject obj)
{}
}
Correct - you don't understand covariance correctly - yet :) Your code would work if you had the same types but as return values, like this:
public delegate object MyDelegate()
public class MyClass
{
public MyClass()
{
_delegate = MyMethod;
}
private MyDelegate _delegate;
public SomeObject MyMethod() { return null; }
}
That would demonstrate covariance. Alternatively, you can keep it as parameters but switch the types around:
public delegate void MyDelegate(SomeObject obj)
public class MyClass
{
public MyClass()
{
_delegate = MyMethod;
}
private MyDelegate _delegate;
public void MyMethod(object obj) {}
}
This now demonstrates contravariance.
My rule of thumb is to ask myself, "given the delegate, what could I do with it? If I can pass in an argument which would break the method, the conversion should have failed. If the method can return something which would break the caller, the conversion should have failed."
In your code, you could have called:
_delegate(new object());
At that point, poor MyMethod has a parameter which is meant to be of type SomeObject, but is actually of type object. This would be a Very Bad Thing, so the compiler stops it from happening.
Does that all make more sense?
Arguments are contravariant, return types are covariant. If the delegate were to be called with an object that is not an instance of SomeObject, you'd have a typing error. On the other hand, returning SomeObject from a routine wrapped in a delegate that returns object is fine.
You need to use a generic.
EDIT: Why? Because as another poster
noted, Object and SomeObject do not
equate to the same thing as Object may
not be SomeObject. This is the whole
point of Generics in the language.
public delegate void MyDelegate<T>(T obj)
public class MyClass
{
public MyClass()
{
_delegate = MyMethod;
}
private MyDelegate<SomeObject> _delegate;
public void MyMethod(SomeObject obj)
{
}
}
The MyDelegate type declares that you can pass any kind of object in. However, MyMethod only takes objects of type SomeObject. What happens if I try to invoke the delegate passing a different kind of object: _delegate("a string object")? According to the declaration of MyDelegate, this should be allowed, but your function MyMethod can't actually receive a string argument.
From the MSDN link you provided
Covariance permits a method to have a
more derived return type than what is
defined in the delegate.
Contravariance permits a method with
parameter types that are less derived
than in the delegate type.
You're attempting to use a more derived parameter type which isn't supported (although .NET 4.0 probably will since this has sorted out many covariance/contravariance issues).
Covariance and Contravariance is about understanding the Is-a-Principle of inheritance.
In both, covariance and contravariance, s.th. is "passed along", either as return value or as an argument to the delegate method. That which is "passed along" has to be "caught" in a receptacle. In C# – or programming jargon as such – we use the word bucket for what I called receptacle. Sometimes you have to fall back to other words in order to catch the meaning of commonly used jargon words.
Anyway, if you understand inheritance, which most likely any reader here will, then the only thing to pay attention to is that the receptacle, i. e. the bucket used for catching has to be of the same type or less derived type than that which is being passed – this being true for both covariance and contravariance.
Inheritance says you can catch a bird in an animal bucket because the bird is an animal. So if a parameter of a method has to catch a bird you could catch it in an animal bucket (a parameter of type animal), which then is contravariance.
And if your method, i.e. your delegate returns a bird, then the "bucket" also can be a of type bird or less derived (of a parent type) meaning the variable where you catch the return value of the method has to be of the same or less derived type than the return value.
Just switch your thinking to discriminate between that which is being passed and that which catches as then all complexity about covariance and contravariance dissolves nicely. Then you realize that the same principle is at work. It is just that inheritance cannot be violated as it flows only one way.
And the compiler is so smart that when you cast the bucket in the more specialized type (again, and as need be) that then and only then you get all the specialized methods back that were added into the more derived class. That is the beauty of it. So it is catch, cast and use what you have and perhaps need.