Can Attributes Be Added Dynamically in C#

Can attributes be added dynamically in C#?

Attributes are static metadata. Assemblies, modules, types, members, parameters, and return values aren't first-class objects in C# (e.g., the System.Type class is merely a reflected representation of a type). You can get an instance of an attribute for a type and change the properties if they're writable but that won't affect the attribute as it is applied to the type.

How can I add CustomAttribute to all object properties dynamically?

I'm having some trouble understanding your question, but let me attempt to clarify.

I have an object with multiple attributes
...
it will erase all CustomAttributes

In C# parlance, class members of the format <access> <type> <name> { get; set; } are referred to as "properties" rather than "attributes." "Attributes," on the other hand, are the C# implementation of annotations, such as the custom attributes to which you are referring.

That said, I currently understand you to mean you have an automatically generated class with multiple properties. You would like each of these properties to have their own custom attributes, but if you edit the class they are removed the next time it is generated, and you cannot get the class generator to include custom attributes.

It might be helpful to know more of the context of your class. How is it being generated, for example? If it is an Entity Framework class, the following SO question may provide some insight:
Add data annotations to a class generated by entity framework. In general, is (or can you make) the generated class partial? If so, then you can still follow the approach in the above question's answer, viz. make your own partial class implementation that provides the properties' custom attributes.

For example, if your generated class looks (or can be made to look) like this:

/// <auto-generated />
public partial class MyClass
{
public int Num1 { get; set; }

public int Num2 { get; set; }

public string Str1 { get; set; }

public string Str2 { get; set; }
}

You could write the other part of the partial class with the custom annotations, like this:

/// human generated
public partial class MyClass
{
[Submit]
public int Num1 { get; set; }

[Submit]
public int Num2 { get; set; }

[Submit]
public string Str1 { get; set; }

[Submit]
public string Str2 { get; set; }
}

Again, without knowing more about your situation, I am not certain if this provides you the information you need, but I hope it at least gives you a starting point.

Edit

If the class is not partial, you might consider wrapping your generated class with a class whose wrapping properties use the custom attribute. For example,

/// human generated
public class MyClassWrapper
{
private readonly MyClass wrapped;

public MyClassWrapper(MyClass wrapped)
{
this.wrapped = wrapped;
}

[Submit]
public int Num1 { get => this.wrapped.Num1; set => this.wrapped.Num1 = value; }

[Submit]
public int Num2 { get => this.wrapped.Num2; set => this.wrapped.Num2 = value; }

[Submit]
public string Str1 { get => this.wrapped.Str1; set => this.wrapped.Str1 = value; }

[Submit]
public string Str2 { get => this.wrapped.Str2; set => this.wrapped.Str2 = value; }
}

Edit 2

If you would rather have a more dynamic solution, at the cost of some design and runtime complexity, you might consider this SO question: How to add property-level Attribute to the TypeDescriptor at runtime?. It seems to address a similar concern --

Really, it's for MS's Application Settings that generates code, so you can't extend it in any way property-wise.

I won't duplicate Gman's explanation entirely here, but essentially this approach consists of

  1. Get the type (MyClass) or an instance of the type myObject
  2. Use TypeDescriptor.GetProvider(MyClass/myObject).GetTypeDescriptor(MyClass/myObject) to get the type or object's baseline ICustomTypeDescriptor
  3. Construct his PropertyOverridingTypeDescriptor with this baseline descriptor
  4. Iterate through MyClass/myObject's properties' definitions with TypeDescriptor.GetProperties(MyClass/myObject). Use TypeDescriptor.CreateProperty to create a new property definition based on the current property's definition, that adds the custom attribute EditorAttribute (or in your case SubmitAttribute), and use the PropertyOverridingTypeDescriptor constructed in 3. to use the new property definition.
  5. Construct his TypeDescriptorOverridingProvider with the PropertyOverridingTypeDescriptor constructed in 3.
  6. Apply the new property definitions to MyClass/myObject with TypeDescriptor.AddProvider

Add Attributes to instance of object at runtime

I don't think you'll be able to accomplish this exactly, since attributes are static metadata.

Can attributes be added dynamically in C#?

A possible workaround could be to create your own custom Attribute that implements all the possible validations (MaxLength, Range, etc.) and have some trigger attached to the object to enable/disable them. This would handle the validation, but not the specific instance mentioned in your question (Html.LabelFor + DisplayName). For that, you could create your own extension method that accesses the DisplayName attribute in the same manner that you add it to the instance.

Change attribute dynamically in code

Those attributes are just properties, you can change those via reflection if you only have that information available dynamically. Once the XAML is parsed and the CLR object created this has nothing to do with XML.

It should be something like

txtTitle.GetType()
.GetProperty(propertyName)
.SetValue(txtTitle, propertyValue);


Related Topics



Leave a reply



Submit