8
votes

Enregistrements c # 9.0 - réflexion et contraintes génériques

Deux questions concernant la nouvelle fonctionnalité des enregistrements:

  1. Comment reconnaître un enregistrement en utilisant la réflexion? en regardant [ici] [1] peut-être y a-t-il un moyen de détecter le EqualityContract mais je ne sais pas si c'est la voie à suivre?

  2. Est-il possible d'avoir une contrainte générique qu'un type générique est un enregistrement? c'est-à-dire s'il est possible d'indiquer que le paramètre de type T doit être une classe d'enregistrement utilisant une contrainte?


6 commentaires

Un pseudo-code pour aider à comprendre le problème?


Qu'est-ce qui n'est pas clair?


Pourquoi demandez-vous cela? Tout d'abord, un disque est toujours une classe. Quant au n ° 2, que voulez-vous dire? Si vous pouvez spécifier que T est un enregistrement? C'est juste une classe, donc probablement non


Je ne sais pas non plus quel est le problème que vous essayez de résoudre, mais ma première pensée en lisant votre histoire a été: pourquoi n'utilise-t-il pas simplement des interfaces?


© kofifus Actuellement, il y a une discussion active sur ce sujet au github de charplang sous un enregistrement de champion. À partir de ce commentaire, vous pouvez lire qu'il y a une intention de ne pas pouvoir dire qu'une classe est un type d'enregistrement. En C # 10 "il n'y aura pas de différence sémantique significative entre un enregistrement et une classe"


Juste pour info, il y a un problème récemment ouvert # 4121 pour déterminer si un type est un enregistrement


4 Réponses :


8
votes
  1. Comment reconnaître un enregistrement en utilisant la réflexion?

Si vous essayez des classes d'enregistrement dans sharplab.io vous verrez que les classes d'enregistrement sont des classes habituelles qui implémentent l' IEquatable<T> et contiennent des membres supplémentaires qui sont utilisés pour comparer et cloner des instances de la classe d'enregistrement. Il n'y a aucun attribut spécial qui indique que la classe est une record class .

Je suppose donc qu'il n'y a aucun moyen de déterminer si une classe est une classe d'enregistrement en utilisant la réflexion.

en regardant ici, il existe peut-être un moyen de détecter le EqualityContract mais je ne suis pas sûr que ce soit la voie à suivre?

Il est possible de déterminer à l'aide de la réflexion si une classe possède une telle propriété, mais ce n'est pas une garantie à 100% que la classe avec une telle propriété est une classe d'enregistrement.


  1. Est-il possible d'avoir une contrainte générique qu'un type générique est un enregistrement? c'est-à-dire s'il est possible d'indiquer que le paramètre de type T doit être une classe d'enregistrement utilisant une contrainte?

Ce n'est pas possible.

  1. La page de proposition d'enregistrements ne contient aucune information sur la spécification qu'un paramètre de type générique T doit être une classe d'enregistrement.
  2. Si vous lisez la discussion sous ce commentaire sur la page des Champion records vous apprendrez qu'il n'y a aucun moyen de spécifier quelque chose comme where T : record en C# 9 . De plus, il est prévu d'éliminer toute différence sémantique significative entre un enregistrement et une classe en C# 10 . Ainsi, les fonctionnalités des enregistrements comme with seront également disponibles pour les classes. L'ajout d' record contrainte d' record rendra cet objectif impossible.

4 commentaires

Merci! 1- "Donc je crois qu'il n'y a aucun moyen de déterminer si une classe est une classe record en utilisant la réflexion" - savez-vous où serait le bon endroit pour demander une réponse définitive? 2- oui je voulais dire "s'il est possible d'indiquer que le paramètre de type T doit être une classe d'enregistrement" donc je suppose que non


peut-être que la réflexion peut détecter le contrat d'égalité?


csharplang équipe de développement de csharplang peut-être des informations supplémentaires (ou des idées) sur l'ajout de la prise en charge des fonctionnalités des questions n ° 1 et n ° 2. Par conséquent, je pense que le mieux est de poser cette question directement à l'équipe de csharplang dans le csharplang github de C # .


perhaps reflection can detect the EqualityContract ? Il est possible de déterminer si une classe a une telle propriété, mais je ne pense pas que ce soit une garantie à 100% que la classe avec une telle propriété est une classe d'enregistrement.



5
votes

En tant que «hack», tous les enregistrements ont une méthode synthétisée <Clone>$ que vous pouvez rechercher. Puisque vous ne pouvez pas écrire une méthode avec ce nom en C #, une classe avec un membre <Clone>$ est garantie d'être un enregistrement à partir de C # 9 .

Cependant, rien ne garantit que cela continuera d'être le cas. Par exemple, il est possible qu'en C # 10.0 certains enregistrements n'aient pas de membre <Clone>$ , ou que certains non-enregistrements en aient.

public static bool IsRecord(Type type) => type.GetMethod("<Clone>$") != null;


2 commentaires

Je ne sais pas pourquoi on ferait ça mais en théorie avec Reflection.Emit vous pourriez demander à quelqu'un de créer un objet qui a une méthode <Clone>$ et qui n'est pas un enregistrement


@nalka bien sûr, et vous pouvez également créer un tel objet dans un langage différent - mais c'est vrai pour tout ce que le compilateur génère, même ceux qui ont un moyen `` officiel '' de les vérifier.



2
votes

Comment reconnaître un enregistrement en utilisant la réflexion?

Comme indiqué ici et ici

Il n'y a pas seulement un moyen officiel de le faire, c'est explicitement contre la conception de la fonctionnalité. L'intention des enregistrements est que, avec un peu de chance, avec C # 10, nous arriverons à un point où faire d'une classe un enregistrement est purement un choix de commodité, et que toutes les autres parties de la fonctionnalité seront réalisables grâce à une forme de syntaxe. Changer un type d'un enregistrement à une classe ne devrait pas être un changement radical, et nous imaginons même qu'un refactoring IDE pourrait automatiquement déplacer un type vers et depuis la syntaxe d'enregistrement sans que les clients ne s'en aperçoivent. Pour C # 9, il y a des endroits où nous n'avons pas tout à fait atteint cet objectif, mais c'est l'objectif.

Malgré ce qui précède, tant qu'il n'y a pas de moyen clair de vérifier si un type a généré automatiquement des Equals et GetHashCode mon objectif ci-dessus ne peut pas être atteint sans déterminer si un type est un enregistrement. Il y a une demande ouverte pour cela ici

Quelques moyens hackers pour détecter les enregistrements qui fonctionnent ATM sont:

  1. vérifier s'il existe une propriété EqualityContract avec l'attribut CompilerGenerated
isRecord = t.GetMethod("<Clone>$") is object;
  1. vérifier <Clone>$ membre comme indiqué par @Yair Halberstadt
isRecord = ((TypeInfo)t).DeclaredProperties.Where(x => x.Name == "EqualityContract").FirstOrDefault()?.GetMethod?.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) is object;

ou une combinaison des deux

Est-il possible d'avoir une contrainte générique qu'un type générique est un enregistrement?

Non


0 commentaires

1
votes

Comme mentionné par tout le monde, il n'est pas possible d'écrire

MyFunc(new MyRecord()); // Works
MyFunc(new MyClass());  // Compiler Error

Vous pouvez cependant créer un enregistrement dont vous faites hériter chaque type d'enregistrement que vous créez. Cela atteindra à peu près ce que vous demandez, même si je ne sais pas ce que j'en pense ...

public abstract record RecordMarker;
public record MyRecord : RecordMarker;
public void MyFunc<T>(T t) where T : RecordMarker
{
}

Avec cela, vous ne pouvez transmettre que des types d'enregistrement car les classes ne peuvent pas hériter des enregistrements.

private void MyFunc<T>(T t) where T : record {...}


1 commentaires

Dotnetfiddle ici: dotnetfiddle.net/vclcpu