« Variance » : différence entre les versions
De Banane Atomic
Aller à la navigationAller à la recherche
(22 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 5 : | Ligne 5 : | ||
= [https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance Description] = | = [https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance Description] = | ||
Variance allows to replace a type with a less-derived (covariance: derived → base) type or a more-derived type (contravariance: base → derived).<br> | |||
It is available for array types, delegate types, and generic types. | |||
= Assignment compatibility = | = Assignment compatibility = | ||
Allow an object of a more derived type ( | Allow an object of a more derived type (derived) to be assigned to an object of a less derived type (base). | ||
<kode lang='cs'> | <kode lang='cs'> | ||
Derived derived; | |||
Base base = derived; | |||
</kode> | </kode> | ||
= Covariance = | = Covariance = | ||
Allow a generic object | Allow a generic object with derived type to be assigned to a generic object of base type. | ||
{{info | It works only with covariant interface}} | {{info | It works only with covariant interface}} | ||
<kode lang='cs'> | <kode lang='cs'> | ||
var | var deriveds = new List<Derived>(); | ||
List< | List<Base> bases = strings; // Cannot convert type List<Base> to List<Derived> because List<T> is invariant | ||
IList< | IList<Base> bases = strings; // Cannot implicitly convert type List<Base> to IList<Derived> because IList<T> is invariant | ||
var bases = (IList<Base>)deriveds; // at execution, Unable to cast List<Derived> to type IList<Base> | |||
IEnumerable< | IEnumerable<Base> bases = deriveds; // IEnumerable<T> is covariant | ||
IReadOnlyList<Base> bases = deriveds; // IReadOnlyList<T> is covariant | |||
IReadOnlyCollection<Base> bases = deriveds; // IReadOnlyCollection<T> is covariant | |||
</kode> | |||
== Create a covariant interface == | |||
<kode lang='cs'> | |||
var derivedVariants = new VariantList<Derived> { new Derived() }; | |||
IVariantList<Base> baseVariants = derivedVariants; | |||
var derivedVariant = new Variant<Derived>(); | |||
IVariant<Base> baseVariant = derivedVariant; | |||
interface IVariantList<out T> { } | |||
class VariantList<T> : List<T>, IVariantList<T> { } | |||
interface IVariant<out T> { } | |||
class Variant<T> : IVariant<T> { } | |||
</kode> | </kode> | ||
= Contravariance = | |||
Allow a generic object with base type to be used for a generic object of derived type. | |||
<kode lang='cs'> | |||
// an equality comparer for Base type, used with Derived objects | |||
class BaseComparer : IEqualityComparer<Base> | |||
{ | |||
public bool Equals(Base? x, Base? y) => x?.Id == y?.Id; | |||
public int GetHashCode(Base obj) => obj.Id; | |||
} | |||
var derived1 = new Derived { Id = 1 }; | |||
var derived1bis = new Derived { Id = 1 }; | |||
var derived2 = new Derived { Id = 2 }; | |||
var baseComparer = new BaseComparer(); | |||
var b3 = baseComparer.Equals(derived1, derived1bis); | |||
var b4 = baseComparer.Equals(derived1, derived2); | |||
</kode> | |||
= [https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/variance-in-generic-interfaces Native variant interfaces] = | |||
{| class="wikitable wtp wtmono1" | |||
! Interface | |||
! Since | |||
|- | |||
| IEnumerable<out T> || .NET Framework 4.0 | |||
|- | |||
| IReadOnlyList<out T> || .NET Framework 4.5 | |||
|- | |||
| IReadOnlyCollection<out T> || .NET Framework 4.5 | |||
|} |
Dernière version du 27 mars 2024 à 16:15
Links
Description
Variance allows to replace a type with a less-derived (covariance: derived → base) type or a more-derived type (contravariance: base → derived).
It is available for array types, delegate types, and generic types.
Assignment compatibility
Allow an object of a more derived type (derived) to be assigned to an object of a less derived type (base).
Derived derived; Base base = derived; |
Covariance
Allow a generic object with derived type to be assigned to a generic object of base type.
It works only with covariant interface |
var deriveds = new List<Derived>(); List<Base> bases = strings; // Cannot convert type List<Base> to List<Derived> because List<T> is invariant IList<Base> bases = strings; // Cannot implicitly convert type List<Base> to IList<Derived> because IList<T> is invariant var bases = (IList<Base>)deriveds; // at execution, Unable to cast List<Derived> to type IList<Base> IEnumerable<Base> bases = deriveds; // IEnumerable<T> is covariant IReadOnlyList<Base> bases = deriveds; // IReadOnlyList<T> is covariant IReadOnlyCollection<Base> bases = deriveds; // IReadOnlyCollection<T> is covariant |
Create a covariant interface
var derivedVariants = new VariantList<Derived> { new Derived() }; IVariantList<Base> baseVariants = derivedVariants; var derivedVariant = new Variant<Derived>(); IVariant<Base> baseVariant = derivedVariant; interface IVariantList<out T> { } class VariantList<T> : List<T>, IVariantList<T> { } interface IVariant<out T> { } class Variant<T> : IVariant<T> { } |
Contravariance
Allow a generic object with base type to be used for a generic object of derived type.
// an equality comparer for Base type, used with Derived objects class BaseComparer : IEqualityComparer<Base> { public bool Equals(Base? x, Base? y) => x?.Id == y?.Id; public int GetHashCode(Base obj) => obj.Id; } var derived1 = new Derived { Id = 1 }; var derived1bis = new Derived { Id = 1 }; var derived2 = new Derived { Id = 2 }; var baseComparer = new BaseComparer(); var b3 = baseComparer.Equals(derived1, derived1bis); var b4 = baseComparer.Equals(derived1, derived2); |
Native variant interfaces
Interface | Since |
---|---|
IEnumerable<out T> | .NET Framework 4.0 |
IReadOnlyList<out T> | .NET Framework 4.5 |
IReadOnlyCollection<out T> | .NET Framework 4.5 |