Existe-t-il un moyen de forcer le compilateur à restreindre l'utilisation d'un attribut personnalisé à utiliser uniquement sur des types de propriétés spécifiques comme int, short, string (tous les types primitifs) ?
similaire à l'énumération ValidOn- AttributeTargetsde AttributeUsageAttribute.
Réponses
Trop de publicités?
Sel
Points
71
Vous pouvez exécuter ce test d'unité pour le vérifier.
Tout d'abord, déclarez l'attribut de validation PropertyType :
[AttributeUsage(AttributeTargets.Class)]
// [JetBrains.Annotations.BaseTypeRequired(typeof(Attribute))] uncomment if you use JetBrains.Annotations
public class PropertyTypeAttribute : Attribute
{
public Type[] Types { get; private set; }
public PropertyTypeAttribute(params Type[] types)
{
Types = types;
}
}
Créer un test unitaire :
[TestClass]
public class TestPropertyType
{
public static Type GetNullableUnderlying(Type nullableType)
{
return Nullable.GetUnderlyingType(nullableType) ?? nullableType;
}
[TestMethod]
public void Test_PropertyType()
{
var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes());
var allPropertyInfos = allTypes.SelectMany(a => a.GetProperties()).ToArray();
foreach (var propertyInfo in allPropertyInfos)
{
var propertyType = GetNullableUnderlying(propertyInfo.PropertyType);
foreach (var attribute in propertyInfo.GetCustomAttributes(true))
{
var attributes = attribute.GetType().GetCustomAttributes(true).OfType<PropertyTypeAttribute>();
foreach (var propertyTypeAttr in attributes)
if (!propertyTypeAttr.Types.Contains(propertyType))
throw new Exception(string.Format(
"Property '{0}.{1}' has invalid type: '{2}'. Allowed types for attribute '{3}': {4}",
propertyInfo.DeclaringType,
propertyInfo.Name,
propertyInfo.PropertyType,
attribute.GetType(),
string.Join(",", propertyTypeAttr.Types.Select(x => "'" + x.ToString() + "'"))));
}
}
}
}
Votre attribut, par exemple n'autorise que les types de propriétés décimales :
[AttributeUsage(AttributeTargets.Property)]
[PropertyType(typeof(decimal))]
public class PriceAttribute : Attribute
{
}
Exemple de modèle :
public class TestModel
{
[Price]
public decimal Price1 { get; set; } // ok
[Price]
public double Price2 { get; set; } // error
}
atornblad
Points
5599
Kleky
Points
41
Le code ci-dessous renvoie une erreur si l'attribut a été placé sur une propriété/champ qui n'est pas Liste de chaîne.
La ligne if (!(value is List<string> list))
peut être une fonction C#6 ou 7.
[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Field, AllowMultiple = false)]
public sealed class RequiredStringListAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (!(value is List<string> list))
return new ValidationResult($"The required attrribute must be of type List<string>");
bool valid = false;
foreach (var item in list)
{
if (!string.IsNullOrWhiteSpace(item))
valid = true;
}
return valid
? ValidationResult.Success
: new ValidationResult($"This field is required"); ;
}
}