55 votes

Pourquoi ne puis-je pas utiliser System.ValueType en tant que contrainte de génériques ?

  • Pourquoi ne puis-je pas utiliser une contrainte de where T : System.ValueType?
  • Pourquoi Microsoft empêche ce type d'être une contrainte?

Exemple :

Pourquoi ne puis-je pas faire ce qui suit ?

// Défini dans une classe .Net
public void bar(T a) where T : ValueType {...}

// Défini dans ma classe
public void foo(T a) where T : ValueType 
{ bar(a); }

Quelle est la différence entre utiliser struct et ValueType ?

// Défini dans ma classe
public void foo(T a) where T : struct 
{ bar(a); }

73voto

Jon Skeet Points 692016

Il y a deux différences entre l'utilisation de

where T : struct

et

where T : ValueType
  • ce dernier permettrait à T d'être ValueType lui-même, qui est un type de référence.
  • ce dernier permettrait également à T d'être un type de valeur nullable

La première de ces différences n'est presque jamais ce que vous voulez. La seconde pourrait occasionnellement être utile ; Nullable est légèrement étrange car il ne satisfait ni la contrainte where T : struct ni la contrainte where T : class.

Plus utile serait la contrainte

where T : struct, System.Enum

qui est interdite en C# pour aucune bonne raison que je puisse dire. Voir mon article de blog et le projet Unconstrained Melody pour plus d'informations à ce sujet.

6 votes

Je dois dire, j'ai toujours me demandé pourquoi nous ne pouvons pas les limiter comme where T : struct, System.Enum. Ce serait tellement utile par moments!

0 votes

Vous pouvez effectivement faire where T: Enum et where T: ValueType en F# (en utilisant sa syntaxe when 'T :> Enum) et en effet, ça fonctionne comme Jon s'y attend. Pour la contrainte de type enum, cela fonctionne avec des énumérations génériques comme enum et System.Enum, et interdit correctement les types de valeur synonymes comme byte ou int. Pour répondre à la question de Jon "pourquoi" il est si difficile d'ajouter à C#, voir cette discussion Roslyn: github.com/dotnet/roslyn/issues/262

0 votes

Je suis arrivé à un point où je veux en fait dire toutes les implémentations concrètes de ValueType incluant nullable. (La contrainte en fait est où T: ValueType, New)

14voto

Rex M Points 80372

ValueType n'est pas la classe de base des types de valeur, c'est simplement un conteneur pour la valeur lorsqu'elle est mise en boîte. Comme il s'agit d'une classe conteneur et non d'une sorte de hiérarchie pour les types réels que vous souhaitez utiliser, il n'est pas utile en tant que contrainte générique.

3 votes

Pas tout à fait et pas complètement. En IL, vous pouvez clairement voir la déclaration de n'importe quel type de valeur ayant extends System.ValueType, ce qui en fait effectivement la classe de base. Je pense que son rôle principal est de servir de marqueur pour distinguer une classe d'un type de valeur, mais je n'en suis pas sûr.

0 votes

La conclusion ("pas utile en tant que contrainte générique") est correcte, mais le reste de la réponse ne l'est pas. ValueType "fournit la classe de base pour les types de valeur." (de docs.microsoft.com/en-us/dotnet/api/…) et aussi "...C'est la classe de base pour tous les types de valeur..." (de docs.microsoft.com/en-us/dotnet/api/…)

6voto

bobbymcr Points 14916

Utiliser struct en tant que contrainte générique est fonctionnellement équivalent à une contrainte "ValueType". En .NET, une struct est un type valeur.

4 votes

Une structure est un ValueType, oui, mais tous les types de valeur ne sont pas des structures, par exemple, ValueType lui-même n'est pas une structure, pas plus que les types de valeur nullable.

1 votes

Je ne pense pas que cette réponse soit correcte, basée sur la réponse acceptée.

0voto

VoteCoffee Points 404

Je pense que l'exemple ci-dessous couvre de nombreux cas d'utilisation que l'on pourrait attendre de ValueType. Le type de paramètre de T? permet les valeurs nulles, et les contraintes de type le restreignent aux structures qui implémentent IFormattable, ce qui est vrai pour les types de valeur courants auxquels je peux penser.

public void foo(T? a) where T : struct, IFormattable

Notez que cela permet des types tels que décimal, datetime, timespan.

https://learn.microsoft.com/en-us/dotnet/api/system.iformattable?view=netcore-3.1

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