Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
.NET Framework 4 ha introdotto il supporto della varianza per diverse interfacce generiche esistenti. Il supporto della varianza consente la conversione implicita di classi che implementano queste interfacce.
A partire da .NET Framework 4, le interfacce seguenti sono varianti:
IEnumerable<T> (T è covariante)
IEnumerator<T> (T è covariante)
IQueryable<T> (T è covariante)
IGrouping<TKey,TElement> (
TKeyeTElementsono covarianti)IComparer<T> (T è controvariante)
IEqualityComparer<T> (T è controvariante)
IComparable<T> (T è controvariante)
A partire da .NET Framework 4.5, le interfacce seguenti sono varianti:
IReadOnlyList<T> (T è covariante)
IReadOnlyCollection<T> (T è covariante)
La Covarianza consente a un metodo di avere un tipo restituito più derivato rispetto a quello definito dal parametro di tipo generico dell'interfaccia. Per illustrare la funzionalità di covarianza, considerare queste interfacce generiche: IEnumerable<Object> e IEnumerable<String>. L'interfaccia IEnumerable<String> non eredita l'interfaccia IEnumerable<Object> . Tuttavia, il String tipo eredita il Object tipo e, in alcuni casi, è possibile assegnare oggetti di queste interfacce l'uno all'altro. Questo è illustrato nell'esempio di codice seguente.
IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;
Nelle versioni precedenti di .NET Framework, questo codice causa un errore di compilazione in C# e, se Option Strict è attivo, in Visual Basic. Ma ora è possibile usare strings invece di objects, come illustrato nell'esempio precedente, perché l'interfaccia IEnumerable<T> è covariante.
La controvarianza consente a un metodo di avere tipi di argomento meno derivati rispetto a quelli specificati dal parametro generico dell'interfaccia. Per illustrare la controvarianza, si supponga di aver creato una BaseComparer classe per confrontare le istanze della BaseClass classe . La classe BaseComparer implementa l'interfaccia IEqualityComparer<BaseClass>. Poiché l'interfaccia IEqualityComparer<T> è ora controvariante, è possibile usare BaseComparer per confrontare le istanze di classi che ereditano la BaseClass classe . Questo è illustrato nell'esempio di codice seguente.
// Simple hierarchy of classes.
class BaseClass { }
class DerivedClass : BaseClass { }
// Comparer class.
class BaseComparer : IEqualityComparer<BaseClass>
{
public int GetHashCode(BaseClass baseInstance)
{
return baseInstance.GetHashCode();
}
public bool Equals(BaseClass x, BaseClass y)
{
return x == y;
}
}
class Program
{
static void Test()
{
IEqualityComparer<BaseClass> baseComparer = new BaseComparer();
// Implicit conversion of IEqualityComparer<BaseClass> to
// IEqualityComparer<DerivedClass>.
IEqualityComparer<DerivedClass> childComparer = baseComparer;
}
}
Per altri esempi, vedere Uso della varianza nelle interfacce per le raccolte generiche (C#).
La varianza nelle interfacce generiche è supportata solo per i tipi di riferimento. I tipi valore non supportano la varianza. Ad esempio, IEnumerable<int> non può essere convertito in modo implicito in IEnumerable<object>perché i numeri interi sono rappresentati da un tipo di valore.
IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler error,
// because int is a value type.
// IEnumerable<Object> objects = integers;
È anche importante ricordare che le classi che implementano interfacce varianti sono ancora invarianti. Ad esempio, anche se List<T> implementa l'interfaccia IEnumerable<T>covariante , non è possibile convertire List<String> in modo implicito in List<Object>. Questo è illustrato nell'esempio di codice seguente.
// The following line generates a compiler error
// because classes are invariant.
// List<Object> list = new List<String>();
// You can use the interface object instead.
IEnumerable<Object> listObjects = new List<String>();