Is there a way to force the compiler to restrict the usage of a custom attribute to be used only on specific property types like int, short, string (all the primitive types)?
similar to the AttributeUsageAttribute's ValidOn-AttributeTargets enumeration.
Creating Custom Attributes (C#)The class name AuthorAttribute is the attribute's name, Author , plus the Attribute suffix. It is derived from System. Attribute , so it is a custom attribute class. The constructor's parameters are the custom attribute's positional parameters.
Attributes are metadata extensions that give additional information to the compiler about the elements in the program code at runtime.
Custom attributes. A custom attribute is a property that you can define to describe assets. Custom attributes extend the meaning of an asset beyond what you can define with the standard attributes. You can create a custom attribute and assign to it a value that is an integer, a range of integers, or a string.
No, you can't, basically. You can limit it to struct
vs class
vs interface
, that is about it. Plus: you can't add attributes to types outside your code anyway (except for via TypeDescriptor
, which isn't the same).
You can run this unit test to check it.
First, declare validation attribute 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; } }
Create unit test:
[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() + "'")))); } } } }
Your attribute, for example allow only decimal property types:
[AttributeUsage(AttributeTargets.Property)] [PropertyType(typeof(decimal))] public class PriceAttribute : Attribute { }
Example model:
public class TestModel { [Price] public decimal Price1 { get; set; } // ok [Price] public double Price2 { get; set; } // error }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With