Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method overload resolution and generic/contravariant interfaces in C#

I think my problem is best explained with a code snippet of my class/interface-hierarchy:

public interface ITransform<D> // or <in D> --> seems to make no difference here
{
    void Transform(D data);
}

interface ISelection {}
interface IValue : ISelection {}

public interface IEditor : ITransform<IValue> {}
public interface ISelector : IEditor, ITransform<ISelection> {}

class Value : IValue { ... }
class Editor : IEditor { ... }              // implements ITransform<IValue>
class Selector : Editor, ISelector { ... }  // implements ITransform<ISelection>

Value v = new Value();
Selector s1 = new Selector();
ISelector s2 = s1;

s1.Transform(v); // resolves to ITransform<ISelection> --> WHY?
s2.Transform(v); // resolves to ITransform<IValue>     --> OK

Question 1: Why does s1.Transform(v) resolve to ITransform<ISelection> and not to ITransform<IValue> as in the second case?

Question 2: For Question 1 it seems to make no difference if ITransform is <D> or <in D>. But do you see any other problems with using <in D> in my class/interface-hierarchy? I'm a bit doubtful because of ISelector which implements ITransform<IValue> and ITransform<ISelection>. Might contravariance cause any problems here because IValue inherits ISelection?

EDIT Just to let you know: I'm currently using Silverlight 4 but I think this is the general C# behaviour.

like image 347
Stephan Avatar asked Mar 02 '12 08:03

Stephan


1 Answers

Your Selector-class implements the ITransform interface which means you'll have to include code to handle Transform(ISelection). Your class can also handle Transform(IValue) but only though inherited methods from the Editor class.

The reason to why it picks the ISelection variant is because that is the variant that is explicitly declared in your Selector class. To pick Transform(IValue) the compiler would have to make an assumption that you rather handle the call from your base class (Editor).

Edit: Some background from C# spec.

Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. For example, the set of candidates for a method invocation does not include methods marked override (§7.4), and methods in a base class are not candidates if any method in a derived class is applicable (§7.6.5.1).

like image 186
maka Avatar answered Nov 16 '22 15:11

maka