Есть ли способ заставить компилятор ограничить использование настраиваемого атрибута, который будет использоваться только для определенных типов свойств, таких как int, short, string (все примитивные типы)?
похожее на AttributeUsageAttribute ValidOn- AttributeTargets перечисление.
Разрешить настраиваемый атрибут только для определенного типа
Ответ 1
Нет, вы не можете, в принципе. Вы можете ограничить его до struct
vs class
vs interface
, то есть об этом. Плюс: вы не можете добавлять атрибуты к типам вне вашего кода в любом случае (кроме как через TypeDescriptor
, что не то же самое).
Ответ 2
Вы можете написать код самостоятельно, чтобы обеспечить правильное использование вашего класса атрибутов, но это как можно больше.
Ответ 3
Вы можете запустить этот unit test, чтобы проверить его.
Сначала объявите атрибут проверки 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;
}
}
Создать 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() + "'"))));
}
}
}
}
Ваш атрибут, например, допускает только десятичные типы свойств:
[AttributeUsage(AttributeTargets.Property)]
[PropertyType(typeof(decimal))]
public class PriceAttribute : Attribute
{
}
Пример модели:
public class TestModel
{
[Price]
public decimal Price1 { get; set; } // ok
[Price]
public double Price2 { get; set; } // error
}