Lambda expression dans l'attribut constructeur
J'ai créé un Attribute
classe appelée RelatedPropertyAttribute
:
[AttributeUsage(AttributeTargets.Property)]
public class RelatedPropertyAttribute: Attribute
{
public string RelatedProperty { get; private set; }
public RelatedPropertyAttribute(string relatedProperty)
{
RelatedProperty = relatedProperty;
}
}
Je l'utilise pour indiquer des propriétés connexes dans une classe. Exemple de la façon dont je voudrais l'utiliser:
public class MyClass
{
public int EmployeeID { get; set; }
[RelatedProperty("EmployeeID")]
public int EmployeeNumber { get; set; }
}
Je voudrais utiliser des expressions lambda afin que je puisse passer d'un type fort dans mon attribut du constructeur, et non pas un "la magie de la chaîne". De cette façon, je peux exploiter compilateur vérification de type. Par exemple:
public class MyClass
{
public int EmployeeID { get; set; }
[RelatedProperty(x => x.EmployeeID)]
public int EmployeeNumber { get; set; }
}
J'ai pensé que je pouvais le faire avec la suite, mais il n'est pas permis par le compilateur:
public RelatedPropertyAttribute<TProperty>(Expression<Func<MyClass, TProperty>> propertyExpression)
{ ... }
Erreur:
La non-générique de type "RelatedPropertyAttribute' ne peut pas être utilisé avec
les arguments de type
Comment puis-je y parvenir?
- essayez de faire la classe générique..au lieu de le seul constructeur.
- Je pense que paramètre d'attribut sont limitées à
compile-time constants, typeof expression or array creation expression of an attribute parameter type
. Vous ne pouvez pas passer même de Décimales comme paramètre. Jetez un oeil à stackoverflow.com/questions/11004909/... - Un type générique ne peut pas dériver de "Attribut" parce que c'est un attribut de la classe
- Peut-être un outil comme [PostSharp][postsharp.net/] peut vous aider à le résoudre. Il peut être intégré dans le processus de génération pour générer du code, avant l' .NET Compilateur est exécutée.
- N'ont pas le temps pour une réponse complète, mais un moyen d'atteindre votre objectif final sera de: faire de la classe une liste statique de
Tuple<,>
s deExpression<Func<class,object>>
s; chaque entrée de cette liste est un tuple de getters de propriétés liées. C'est ensuite au moment de la compilation forte, et aussi interrogable au moment de l'exécution.
Vous devez vous connecter pour publier un commentaire.
Vous ne pouvez pas
[Foo<SomeType>]
) est définiAvoir un générique attribut n'est pas possible de façon conventionnelle. Cependant, C# et VB n'est pas prise en charge, mais le CLR ne. Si vous voulez écrire un peu de code IL il est possible.
Prenons votre code:
Compiler le code, de s'ouvrir à l'assemblée ILSpy ou ILDasm et vider le contenu d'un
fichier texte. Le IL de vous attribuer la déclaration de classe ressemble à ceci:
Dans le fichier texte, vous pouvez alors faire de l'attribut générique. Il y a plusieurs choses qui doivent être changées.
Cela peut être fait en changeant le IL et le CLR ne se plaignent:
et maintenant, vous pouvez modifier le type de relatedProperty de chaîne à votre type générique.
Par Exemple:
le modifier:
Il y a beaucoup de cadres pour faire un "sale" boulot comme ça: Mono.Cecil ou La CCI.
Comme je l'ai déjà dit, il n'est pas propre objet orienté solution mais je voulais juste souligner une autre façon de briser la limite de C# et VB.
Il y a une intéressante lecture autour de ce thème, check it out ce livre.
Espère que cela aide.
Si vous êtes à l'aide de C# 6.0, vous pouvez utiliser nameof
avec elle, vous pouvez utiliser votre attribut comme ceci:
L'une des solutions possibles est de définir la classe pour chaque propriété de la relation et de le référencer
typeof() de l'opérateur dans l'attribut constructeur.
Mise à jour:
Par exemple:
Vous ne pouvez pas. Les types des attributs sont limitées comme l'écrit ici. Ma suggestion, essayez d'évaluer votre expression lambda à l'extérieur, puis utilisez l'un des types suivants:
De s'étendre sur les mon commentaire, c'est une façon de réaliser votre tâche avec une approche différente. Vous dites que vous voulez "indiquent des propriétés connexes dans une classe", et que "vous souhaitez utiliser des expressions lambda afin que je puisse passer d'un type fort dans mon attribut du constructeur, et non pas un "la magie de la chaîne". De cette façon, je peux exploiter compilateur de vérifier le type".
Ici est donc un moyen d'indiquer des propriétés liées à la qui est au moment de la compilation tapé et n'a pas toute la magie des cordes:
C'est la classe considérée. Nous voulons indiquer que
EmployeeId
etEmployeeNumber
sont liées. Pour un peu de code de la concision, nous allons mettre en œuvre ce type d'alias jusqu'en haut du fichier de code. Il n'est pas nécessaire du tout, mais il ne rendre le code moins intimidant:Ce fait
MyClassPropertyTuple
un alias pour unTuple
de deuxExpression
s, dont chacun saisit la définition d'une fonction à partir d'unMyClass
à un objet. Par exemple, la propriété des getters surMyClass
sont de telles fonctions.Maintenant, nous allons saisir la relation. Ici, j'ai fait une statique propery sur
MyClass
, mais cette liste pourrait être définie n'importe où:Le compilateur C# sait que nous sommes la construction d'un
Tuple
deExpression
s, de sorte que nous n'avons pas besoin des conversions explicites en face de ces expressions lambda - ils sont automatiquement mis enExpression
s.C'est essentiellement en termes de définition, ceux
EmployeeId
etEmployeeNumber
mentionne sont fortement typés et appliquées au moment de la compilation, et le refactoring qui n'propriété renomme devrait être en mesure de trouver ces usages lors d'un changement de nom (ReSharper peut certainement). Il n'y a pas la magie des cordes ici.Mais bien sûr, nous voulons aussi être en mesure d'interroger les relations au moment de l'exécution (j'assume!). Je ne sais pas exactement comment vous souhaitez le faire si ce code est juste à titre indicatif.
Le code pour
propertyInfo1FromExpression
etpropertyInfo2FromExpression
ici, j'ai travaillé avec l'utilisation judicieuse de la fenêtre d'observation pendant le débogage, ce qui est habituellement la façon dont je travaille ce qu'uneExpression
arbre contient en fait.L'exécution de cette volonté de produire
de montrer que nous pouvons réussir à extraire les détails des propriétés, et (cruciale) ils sont de référence identique à la
PropertyInfo
s obtenus par d'autres moyens. Nous espérons que vous pouvez utiliser ceci en conjonction avec quelle que soit l'approche que vous êtes en train d'utiliser pour spécifier les propriétés d'intérêt au moment de l'exécution.Pointe. Utilisation nameof. J'ai un DateRangeAttribute qui valide les deux propriétés et permet de s'assurer qu'ils sont valides DateRange.