Attributes vs. CustomAttributes in PropertyInfo - c#

I've been working with Reflections and wanted to get all the attributes declared for a property. There are two properties under PropertInfo class which are CustomAttributes and Attributes.
According to the MSDN, they are explained as follows:
Attributes:
This property represents the attributes associated with a member. All
members have a set of attributes that are defined in relation to the
specific type of member. The property attributes let the user know if
this property is the default property, a SpecialName property, and so
on.
Note: The code sample given in the PropertyInfo.Attributes page doesn't even work.
Custom Attributes:
An array that contains all the custom attributes applied to this
member, or an array with zero elements if no attributes are defined.
However, when I run this code for them, Attributes returns nothing while CustomAttributes returns Required.
void Main()
{
var attributes = typeof(Myproperty).GetProperty("Caption").CustomAttributes;
//var attributes = typeof(Myproperty).GetProperty("Caption").Attributes;
attributes.Dump(); //Dump is a LinqPad method which dumps everything to the outpu window
}
public class Myproperty
{
private string caption = "Default caption";
[Required]
public string Caption
{
get{return caption;}
set {if(caption!=value) {caption = value;}
}
}
}

PropertyInfo.Attributes doesn't have anything to do with the Attribute class. Check the PropertyAttributes enumeration for values you may encounter. These are CLR implementation details that have no obvious connection to C# code. Yes, that was an unfortunate naming choice.
To find attributes like your [Required] attribute you must use the CustomAttributes property.

Related

Usage of C# attribute methods

In C#, what is the purpose of methods declared in attributes and how are they used?
As an example, have a look at the attribute MaxLengthAttribute: it has a bunch of methods. One of them is the IsValid() method, which is used to validate the property the attribute is applied to. How is this validation performed? I suppose the IsValid() method is called against the property, but I don't find documentation on how to call attribute methods.
Note: I have a Java background. In Java, annotations are intended as metadata and are declared as #intefaces, thus they don't have methods.
In almost all cases, the answer is simply: manually but by code that isn't yours. Some piece of code in some framework that you're using is intentionally checking for those attributes, and then if they exist: materializing them (preferably also with some kind of caching), and invoking the method.
Attributes don't do anything by themselves, but they are still types and can be materialized via the reflection APIs. If you want to write code to do this:
using System;
[SomeAttribute("boop")]
static class P
{
static void Main()
{
var obj = (SomeAttribute)Attribute.GetCustomAttribute(
typeof(P), typeof(SomeAttribute));
// note the attribute doesn't know the context
// so we need to pass that *in*; an attribute
// doesn't know what it has been attached to
obj?.DoSomething(typeof(P));
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct
| AttributeTargets.Enum)]
class SomeAttribute : Attribute
{
public string Name { get; }
public SomeAttribute(string name)
=> Name = name;
public void DoSomething(Type type)
=> Console.WriteLine($"hey {type.Name} - {Name}");
}
Basically an attribute does nothing in itself, it has to be analysed by some kind of framework. What this framework actually does is completely up to the attributes creator. So the framework may just check if an attribute is present, however it can of course also call its members.
So imagine you have this code:
[MyAttribute]
class MyClass
{
}
class MyAttribute : Attribute
{
public void DoSomething();
}
Now you have some code that checks if the attribuite is present and if so calls DoSomething:
// get types with the attribute
var typesAndAttributes= myAssembly.GetTypes().Select(x => new
{
Type = x,
Attribute = Attribute.GetCustomAttribute(x, typeof(MyAttribute))
});
// now call DoSomething for every attribute
forerach(var e in typesAndAttributes)
{
e.Attribute?.DoSomething();
}
In your example of MaxLengthAttribute this means the following. If you´d decorate your member like this:
MaxLengthAttribute(2)
public int[] MyArr = new int[3];
and execute the code the framework calls IsValid for MyArr and will probably (not sure about it, didn´t inspect the sourcecode) return false, as the value contains 3 elements although only two are considered valid.
As an example, have a look at the attribute MaxLengthAttribute: it has a bunch of methods. One of them is the IsValid() method, which is used to validate the property the attribute is applied to. How is this validation performed? I suppose the IsValid() method is called against the property, but I don't find documentation on how to call attribute methods.
Here's a very simple example:
// Start off with an object we're going to validate
public class Foo
{
[MaxLength(5)]
public string Bar { get; set; }
}
var objectToValidate = new Foo() { Bar = "123456" };
// Use reflection to get a list of properties on the object
var properties = objectToValidate.GetType().GetProperties();
foreach (var property in properties)
{
// For each property, get the attributes defined on that property
// which derive from the ValidationAttribute base class
var attributes = property.GetCustomAttributes<ValidationAttribute>();
var propertyValue = property.GetValue(objectToValidate);
foreach (var attribute in attributes)
{
// For each attribute, call its IsValid method, passing in the value
// of the property
bool isValid = attribute.IsValid(propertyValue);
if (!isValid)
{
Console.WriteLine("{0} is invalid", property.Name);
}
}
}
This is more or less what Validator.ValidateObject does, except with a lot more caching.
(In the case of the DataAnnotations methods, the TypeDescriptor infrastructure is actually used. This lets you effectively add attributes to classes and their properties without modifying the source of the class directly).
Runnable example

Passing Attributes of a Auto-Implemented Property to its field

I have the following Problem: I would like to add an attribute to an auto-implemented property prop of a class Foo in the first step.
In a second step I'm iterating over all fields of Foo and I copy values to these fields (values of fields of auto-implemented Properties are also found and copied). In this part I need access to the information of the Attribute.
class FieldSetter
{
// This Method is called from outside and should work for any class
private void SetFieldValues(object unknownObject)
{
foreach (var field in
unknownObject.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.Static).Where((field) => !field.IsLiteral))
{
if (!EvalAttribute(Attribute.GetCustomAttributes(field))) // the Attribute should be accessed here
{
// Do something if no special Information is set
field.SetValue(a, "default Value");
}
else
{
// Do special things
field.SetValue(a, "special Value");
}
}
}
internal static bool EvalAttribute(Attribute[] attributes)
{
foreach (System.Attribute attr in attributes)
{
var myAttr = attr as MyAttribute;
if (myAttr != null)
{
if (myAttr.SomeAttributeValues == "Specific Attribute Value")
{
return true;
}
}
}
return false;
}
}
// This class is a example for how a given Object can look like
class Foo
{
[MyAttribute("Example Information")] // This Attribute won't be accessed via prop-Field
int prop { get; set; }
[MyAttribute("Another Example Information")] // This Attribute won't be accessed via prop-Field
int field;
//... lots of other fields and properties
}
[System.AttributeUsage(System.AttributeTargets.All)]
class MyAttribute : Attribute
{
public MyAttribute(string someInformation)
{
SomeAttributeValues = someInformation;
}
public string SomeAttributeValues;
}
You can't do this. If you need to have the attribute on the field, you need to declare the field yourself and not use auto-properties. Alternately, you can reflect over the properties which will have the attribute when you look for them.
If you can guarantee that the properties you're interested in will always be auto-implemented, and you have some idea of what compiler will be used to compile the types you're interested in, you could leverage the fact that the backing fields for auto-generated properties follow a specific naming convention. For example, the code you've provided ends up with a field name like this:
<prop>k__BackingField
This is a distinctive name, which cannot be produced directly by C# code, so if you run into a field with a name like this you could parse out the property name from between the angle brackets, and use GetProperty() on that name.
However, this is a hacky solution because:
The name used for backing fields is an implementation detail, which could theoretically change in future versions of .NET, or for alternative compilers like Mono.
There's nothing to ensure that the fields you find will always be tied to auto-properties. What would your expectations be if you ran into this?
class Foo
{
int field;
[MyAttribute("Example Information")]
int prop { get{return field;} set {return field;} }
//... lots of other fields and properties
}
I'd strongly suggest that you spend more time analyzing what your real business need and constraints are, and see if there's not another, more robust way to approach this problem.

Can you create a custom attribute in c# with "hidden" properties?

Normally when you create a custom Attribute class, any public property with a getter and a setter is automatically exposed to the person applying the attribute on the class, so that the person using the attribute can specify the value of that property.
I want a custom attribute class which exposes a getter and setter for a particular property, but which does not allow this property to be specified as a named argument to the attribute on creation. Example:
[AttributeUsage(AttributeTargets.Class)]
class MyCustomAttribute : Attribute
{
public bool MyProperty
{
get { /* do something */ }
set { /* do something */ }
}
}
// The following line should be a compiler error, MyProperty should
// be hidden for attribute initialization!
[MyCustomAttribute(MyProperty=true)]
class MyClass
{
};
Is there any way to achieve this?
You could simply make the property (or just the property setter) internal, if you intend to use it elsewhere in your code, but don't want others to see it.
Alternatively, if you want to expose the property other users, but just disallow setting it in the declarative syntax, you could not expose a property setter, but provide a different method to set the value if you need to:
class MyCustomAttribute : Attribute
{
public bool MyProperty
{
get { /* do something */ }
}
public void SetMyProperty(bool value)
{
/* do something */
}
}
If the property is public, there is no way of preventing it from being assigned when the attribute is applied. As suggested by dtb in the comments, you could use getter and setter methods instead, but that probably wouldn't help you...
Attributes are not made to be modified at runtime. When you retrieve the attributes from a class or member (or anything else) using reflection, you only get copies of these attributes, so even if you modified them, the next time you would retrieve them, you would get a fresh, unmodified copy.

How does PropertyDescriptor.ResetValue Method determine default value of property

I have implemented a custom class and tried to set its default value by calling PropertyDescriptor.ResetValue Method. When i make some researches in internet, i saw a link in msdn about this method, its usage and how can be used.
http://msdn.microsoft.com/en-us/library/system.componentmodel.propertydescriptor.resetvalue.aspx
According to this link, msdn document says:
This method determines the value to reset the property to in the following order of precedence:
1- There is a shadowed property for this property.
2- There is a DefaultValueAttribute for this property.
3- There is a "ResetMyProperty" method that you have implemented, where "MyProperty" is the name of the property you pass to it.
Second methodology does not correspond to my needs. On the other hand, there are not enough usage samples of first and third items.
Could you please explain expecially third one?
I don't know about the first option (I suspect it's to do with declaring one property in a base class and a "new" property in a derived class), but the third seems pretty simple to me:
public class Foo
{
public string Name { get; set; }
public Foo()
{
ResetName();
}
public void ResetName()
{
Name = "Some default value";
}
}
The documentation is saying that if you call ResetValue on the PropertyDescriptor for the Name property, it will call the ResetName method on the component.
I've never actually tried this, but that would be my interpretation.
You can retrieve (2) DefaultValueAttribute like this:
public class MyClass
{
[DefaultValue("my default value")]
public string MyVar { get; set; }
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(typeof(MyClass)))
string defaultValue = descriptor.Attributes.OfType<DefaultValueAttribute>().First().Value.ToString();

how to serialize some attribute in some condition

When using XML serialization to serialize a class, how to make some attribute be outputted conditionally. i.e. In some case, it output this attribute, in other cases, it does not.
You can create an additional property which is called MyPropertySpecified, which returns a boolean.
When this property returns true, the MyProperty property will be serialized. When it returns false, it will not be serialized.
Also, you'd want to decorate that property with the XmlIgnoreAttribute, so that this specific property is not serialized.
Example:
public class Person
{
public string Name
{
get;
set;
}
[XmlIgnore]
public bool NameSpecified
{
get { return Name != "secret"; }
}
}
While works and is a rather short solution, the propertyNameSpecified pattern has some drawbacks in my opinion (pollutes the interface of your class; relies on property names; introduces implicit behavior).
If you only need to implement a simple condition (e.g. don't serialize a default value), then the DefaultValue attribute is a better choice.
For example:
public class PurchaseOrder
{
[DefaultValue("2002")]
public string Year;
}
If Year has the value "2002", it will be omitted from the XML output.
You can use OnSerializingAttribute while serializing which allows us to invoke method before serialization. You can get more information about it here
Imho you would need to implement IXmlSerializable on the class and implement the WriteXml and ReadXml methods in such a way that they only write the attribute based upon the conditions you specify and can handle reading with or without that particular attribute present upon deserialization.
IXmlSerializable at Msdn

Categories

Resources