175 votes

La Covariance et la contravariance l'exemple du monde réel

Je vais avoir un peu de mal à understaing comment je pourrais utiliser la covariance et la contravariance dans le monde réel.

Jusqu'à présent, le seul exemple que j'ai vu ont été le même exemple du tableau.

object[] objectArray = new string[] { "string 1", "string 2" };

Il serait agréable de voir un exemple qui me permettrait de l'utiliser au cours de ma formation si je pouvais voir qu'il est utilisé ailleurs.

Quelqu'un peut-il m'indiquer quelques ressources utiles?

148voto

Marcelo Cantos Points 91211
// Contravariance
interface IGobbler<in T> {
    void gobble(T t);
}

// Since a QuadrupedGobbler can gobble any four-footed
// creature, it is OK to treat it as a donkey gobbler.
IGobbler<Donkey> dg = new QuadrupedGobbler();
dg.gobble(MyDonkey());

// Covariance
interface ISpewer<out T> {
    T spew();
}

// A MouseSpewer obviously spews rodents (all mice are
// rodents), so we can treat it as a rodent spewer.
ISpewer<Rodent> rs = new MouseSpewer();
Rodent r = rs.spew();

Pour être complet...

// Invariance
interface IHat<T> {
    void hide(T t);
    T pull();
}

// A RabbitHat…
IHat<Rabbit> rHat = RabbitHat();

// …cannot be treated covariantly as a mammal hat…
IHat<Mammal> mHat = rHat;      // Compiler error
// …because…
mHat.hide(new Dolphin());      // Hide a dolphin in a rabbit hat??

// It also cannot be treated contravariantly as a cottontail hat…
IHat<CottonTail> cHat = rHat;  // Compiler error
// …because…
rHat.hide(new MarshRabbit());
cHat.pull();                   // Pull a marsh rabbit out of a cottontail hat??

118voto

tvanfosson Points 268301

Disons que vous avez une Personne de la classe, et une classe qui en dérive, Professeur. Vous avez quelques opérations qui prennent un IEnumerable<Person> comme argument. Dans votre classe d'École, vous avez une méthode qui retourne un IEnumerable<Teacher>. La Covariance permet d'utiliser directement qui en résultent pour les méthodes qui prennent un IEnumerable<Person>.

 public class Person { } 

 public class Teacher : Person { } 

 public class MailingList
 {
       public void Add( IEnumerable<Person> people ) { ... }
 }

 public class School
 {
       public IEnumerable<Teacher> GetTeachers() { ... }
 }

 ...

 var teachers = school.GetTeachers();
 var mailingList = new MailingList();
 mailingList.Add( teachers );

58voto

Jack Points 845

Le dans et hors contrôle par mots-clés le compilateur de règles de conversion pour les délégués et les interfaces avec les paramètres génériques:

interface IInvariant<T> {
    // This interface can not be implicitly cast AT ALL
    // Used for non-readonly collections
    IList<T> GetList { get; }
    // Used when T is used as both argument *and* return type
    T Method(T argument);
}//interface

interface ICovariant<out T> {
    // This interface can be implicitly cast to LESS DERIVED (upcasting)
    // Used for readonly collections
    IEnumerable<T> GetList { get; }
    // Used when T is used as return type
    T Method();
}//interface

interface IContravariant<in T> {
    // This interface can be implicitly cast to MORE DERIVED (downcasting)
    // Usually means T is used as argument
    void Method(T argument);
}//interface

class Casting {

    IInvariant<Animal> invariantAnimal;
    ICovariant<Animal> covariantAnimal;
    IContravariant<Animal> contravariantAnimal;

    IInvariant<Fish> invariantFish;
    ICovariant<Fish> covariantFish;
    IContravariant<Fish> contravariantFish;

    public void Go() {

        invariantAnimal = invariantFish; // NOT ALLOWED invariants do *not* allow implicit casting
        invariantFish = invariantAnimal; // NOT ALLOWED

        covariantAnimal = covariantFish; // ALLOWED covariants *allow* implicit upcasting
        covariantFish = covariantAnimal; // NOT ALLOWED covariants do *not* allow implicit downcasting

        contravariantAnimal = contravariantFish; // NOT ALLOWED contravariants do *not* allow implicit upcasting
        contravariantFish = contravariantAnimal; // ALLOWED contravariants *allow* implicit downcasting

    }//method

}//class

// .NET Framework Examples:
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable { }
public interface IEnumerable<out T> : IEnumerable { }


class Delegates {

    // When T is used as both "in" (argument) and "out" (return value)
    delegate T Invariant<T>(T argument);

    // When T is used as "out" (return value) only
    delegate T Covariant<out T>();

    // When T is used as "in" (argument) only
    delegate void Contravariant<in T>(T argument);

    // Confusing
    delegate T CovariantBoth<out T>(T argument);

    // Confusing
    delegate T ContravariantBoth<in T>(T argument);

    // From .NET Framework:
    public delegate void Action<in T>(T obj);
    public delegate TResult Func<in T, out TResult>(T arg);

}//class

32voto

Michael Stum Points 72046
class A {}
class B : A {}

public void SomeFunction()
{
    var someListOfB = new List<B>();
    someListOfB.Add(new B());
    someListOfB.Add(new B());
    someListOfB.Add(new B());
    SomeFunctionThatTakesA(someListOfB);
}

public void SomeFunctionThatTakesA(IEnumerable<A> input)
{
    // Before C# 4, you couldn't pass in List<B>:
    // cannot convert from
    // 'System.Collections.Generic.List<ConsoleApplication1.B>' to
    // 'System.Collections.Generic.IEnumerable<ConsoleApplication1.A>'
}

Fondamentalement, chaque fois que vous avez eu une fonction qui prend une Énumération d'un certain type, vous ne pouviez pas passer dans une Énumération d'un type dérivé sans explicitement casting.

Juste pour vous avertir d'un piège:

var ListOfB = new List<B>();
if(ListOfB is IEnumerable<A>)
{
    // In C# 4, this branch will
    // execute...
    Console.Write("It is A");
}
else if (ListOfB is IEnumerable<B>)
{
    // ...but in C# 3 and earlier,
    // this one will execute instead.
    Console.Write("It is B");
}

C'est horrible de code de toute façon, mais il n'existe pas et que le changement de comportement en C# 4 peut introduire subtils et difficiles à trouver des bugs si vous utilisez une construction de ce genre.

5voto

Hun1Ahpu Points 2119

Ici vous pouvez trouver 2 exemples simples de la Covariance et la contravariance pour les délégués.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X