The following is a question I've seen on a test which raised some questions:
Given the following code:
public delegate B func(B b);
public class A
{
public func x;
public int i = 2;
public A(int i) { this.i = i; x += f; }
public virtual C f(A a) { Console.WriteLine("C A.f(A)"); return new C(1); }
public virtual A f(C c) { Console.WriteLine("A A.f(C)"); return new A(2); }
}
public class B: A{
public B(int i) : base(i) { x += f; }
public virtual B f(B b) { Console.WriteLine("B B.f(B)"); return new B(3); }
public new C f(A a) { Console.WriteLine("C B.f(A)"); return new C(4); }
}
public class C: B{
public C(int i) : base(i) { x += f; }
public new B f(B b) { Console.WriteLine("B C.f(B)"); return new C(5); }
public override A f(C c) { Console.WriteLine("A C.f(C)"); return new A(6); }
}
with the following main:
static void Main(string[] args)
{
C c = new C(12);
A a = c.x(c);
Console.WriteLine(a.i);
}
- What is the output?
- What happens if we change the delegate definition to:
public delegate C func(B b);
- What happens when we change the delegate definition to
public delegate T func<T,U>(U u);
and changex
in A topublic func<B,B> x;
?
The official answers were:
To #1:
C A.f(A)
B B.f(B)
B C.f(B)
5
To #2:
It won't compile because the method that are added to x
in class B and C are chosen based on the static type of the argument. So in class B B B.f(B)
needs to be added but the return type doesn't match, and in class C B C.f(B)
needs to be added but the return type doesn't match.
To #3:
It prints the same answer as #1 since both definitions are equivalent.
Here is what I don't understand:
- How are the methods which are added to
x
in the linex+=f;
chosen out of all the overloaded options? Is the overloaded method with the "closest" argument type to the dynamic type of "this" the one chosen? - Aren't generic delegates non variant unless declared with
in
andout
? How does the answer to #3 make sense?