Подтвердить что ты не робот

Разрешить настраиваемый атрибут только для определенного типа

Есть ли способ заставить компилятор ограничить использование настраиваемого атрибута, который будет использоваться только для определенных типов свойств, таких как int, short, string (все примитивные типы)?
похожее на AttributeUsageAttribute ValidOn- AttributeTargets перечисление.

4b9b3361

Ответ 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
}