Method overload resolution and generic / contravariant interfaces in C #

I think my problem is best explained by the 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 s1.Transform(v) allow ITransform<ISelection> and not ITransform<IValue> , as in the second case?

Question 2: For question 1, it does not seem to matter if ITransform is <D> or <in D> . But do you see any other problems using <in D> in my class / interface hierarchy? I doubt a bit about ISelector , which implements ITransform<IValue> and ITransform<ISelection> . Perhaps contravariance is causing any problems because IValue inherits ISelection ?

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

+7
source share
3 answers

Your Selector class implements the ITransform interface, which means that you will need to include code for processing Transform (ISelection). Your class can also handle Transform (IValue), but only inherited methods from the Editor class.

The reason why he chooses the ISelection option is because it is an option explicitly declared in your Selector class. To select Transform (IValue), the compiler would have to assume that you would rather handle the call from your base class (Editor).

Edit: some background from C # spec.

Each of these contexts defines a set of candidate candidate elements and a list of arguments in its own way, as described in detail in the sections listed above. For example, a set of candidates for a method call does not include methods marked with override (ยง7.4), and methods in the base class are not candidates if they are a method in the derived class is applicable (ยง7.6.5.1).

+2
source

In Q1, I think this is because the compiler will look for a shorter hierarchy chain to get a valid overload. To get ITransform on S1, you will need to go further.

 s1->Selector->ISelector->ITransform<Selector> s1->Selector->Editor->IEditor->ITransform<IValue> s1->Selector->ISelector->IEditor->ITransform<IValue> 

I will look for a source for verification.

0
source

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

For me, this is allowed by Selector.Transform<ISelection> . In addition, it should: you said that it is a selector, and the Selector has an open method called Transform, and it accepts ISelection. IValue extends ISelection. When will he be forced to ITransform? I do not believe that this illustrates any contravariance; I think it is an implicit transformation.

Question 2: For Question 1, it does not seem to matter if ITransform in or an invariant

since you use the generic parameter as the arg method, and not the return type, the rules determine that the parameter must be contravariantly valid, which would allow in and disable out .

 public class Example { public interface ITransform<D> // or <in D> --> seems to make no difference here { void Transform(D data); //contravariant in ITranform<out D>. //D Transform(string input); //covariance ok } public interface ISelection { } public interface IValue : ISelection { } public interface IEditor : ITransform<IValue> { } public interface ISelector : IEditor, ITransform<ISelection> { new void Transform(ISelection data); } class Value : IValue { } class Editor : IEditor { public void Transform(IValue data) { throw new NotImplementedException(); } } class Foo : Editor, ISelector { public void Transform(ISelection data) { throw new NotImplementedException(); } } public void Whatever() { Value v = new Value(); Foo s1 = new Foo(); IEditor s2 = s1; s1.Transform(v); // resolves to Foo.Tranform(ISelection) s2.Transform(v); // resolves to ITransform<IValue> --> cast into IEditor, which sig says ITransform<IValue> } } 
0
source

All Articles