Deux questions concernant la nouvelle fonctionnalité des enregistrements:
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?
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?
4 Réponses :
- 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.
- 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.
T
doit être une classe d'enregistrement.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.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;
Comment reconnaître un enregistrement en utilisant la réflexion?
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
etGetHashCode
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 iciQuelques moyens hackers pour détecter les enregistrements qui fonctionnent ATM sont:
- vérifier s'il existe une propriété
EqualityContract
avec l'attributCompilerGenerated
isRecord = t.GetMethod("<Clone>$") is object;
- vérifier
<Clone>$
membre comme indiqué par @Yair HalberstadtisRecord = ((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
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 {...}