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

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

//Get PropertyDescriptor object for the given property name
var propDesc = TypeDescriptor.GetProperties(typeof(T))[propName];

//Get FillAttributes methodinfo delegate
var methodInfo = propDesc.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public |
                                                      BindingFlags.NonPublic)
    .FirstOrDefault(m => m.IsFamily || m.IsPublic && m.Name == "FillAttributes");

//Create Validation attribute
var attribute = new RequiredAttribute();
var  attributes= new ValidationAttribute[]{attribute};

//Invoke FillAttribute method
methodInfo.Invoke(propDesc, new object[] { attributes });

Привет. Я пытаюсь добавить атрибут Validation во время выполнения, используя приведенный выше код. Однако я получаю следующее исключение:

Коллекция имела фиксированный размер

4b9b3361

Ответ 1

Не позволяйте кому-то говорить вам, вы не можете этого сделать. Вы можете баллотироваться на пост президента, если хотите: -)

Для вашего удобства это полностью рабочий пример.

    public class SomeAttribute : Attribute
    {
        public SomeAttribute(string value)
        {
            this.Value = value;
        }

        public string Value { get; set; }
    }

    public class SomeClass
    {
        public string Value = "Test";
    }

    [TestMethod]
    public void CanAddAttribute()
    {
        var type = typeof(SomeClass);

        var aName = new System.Reflection.AssemblyName("SomeNamespace");
        var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
        var mb = ab.DefineDynamicModule(aName.Name);
        var tb = mb.DefineType(type.Name + "Proxy",System.Reflection.TypeAttributes.Public, type);

        var attrCtorParams = new Type[] { typeof(string) };
        var attrCtorInfo = typeof(SomeAttribute).GetConstructor(attrCtorParams);
        var attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { "Some Value" });
        tb.SetCustomAttribute(attrBuilder);

        var newType = tb.CreateType();
        var instance = (SomeClass)Activator.CreateInstance(newType);

        Assert.AreEqual("Test", instance.Value);
        var attr = (SomeAttribute)instance.GetType().GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault();
        Assert.IsNotNull(attr);
        Assert.AreEqual(attr.Value, "Some Value");

    }

Ответ 3

Это не wokring, потому что метод FillAttributes ожидает параметр типа IList, и вы передаете массив. Ниже приведена реализация MemberDescriptor.FillAttributes:

protected virtual void FillAttributes(IList attributeList) { 
    if (originalAttributes != null) {
        foreach (Attribute attr in originalAttributes) {
            attributeList.Add(attr);
        } 
    }
}

Как вы видите, FillAttributes просто заполняет параметр attributeList всеми атрибутами вашего свойства. И чтобы изменить работу вашего кода var attributes= new ValidationAttribute[]{attribute}; с помощью:

var attributes = new ArrayList { attribute };

Этот код не имеет ничего с добавлением атрибутов к свойству типа во время выполнения. Это "добавление атрибута к PropertyDescriptor", извлеченного из типа, и не имеет смысла, если вы не пытаетесь создать тип во время выполнения, который основан на уже существующем типе.

Ответ 4

использовать FastDeepCloner

public class test{
public string Name{ get; set; }
}

var prop = now DeepCloner.GetFastDeepClonerProperties(typeof(test)).First();
prop.Attributes.Add(new JsonIgnoreAttribute());
// now test and se if exist 
prop = now DeepCloner.GetFastDeepClonerProperties(typeof(test)).First();
bool containAttr = prop.ContainAttribute<JsonIgnoreAttribute>()
// or 
JsonIgnoreAttribute myAttr = prop.GetCustomAttribute<JsonIgnoreAttribute>();