Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow a custom Attribute only on specific type

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.

like image 764
gdoron is supporting Monica Avatar asked Dec 05 '11 08:12

gdoron is supporting Monica


People also ask

How do you write a custom attribute?

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.

What are custom attributes in C#?

Attributes are metadata extensions that give additional information to the compiler about the elements in the program code at runtime.

What is custom attribute?

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.


2 Answers

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).

like image 165
Marc Gravell Avatar answered Sep 21 '22 21:09

Marc Gravell


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 } 
like image 31
Sel Avatar answered Sep 20 '22 21:09

Sel