.NET Attributes on Property - c#

If I have:
[SomeAttr]
public Int32 SomeProperty
{
get; set;
}
Is it possible for SomeAttr to tell what property it's tacked onto? Is it atleast possible to tell what Type the property is?

No. You can only do it the other way around. You can query the property (through reflection) what attributes it has:
Attribute.GetCustomAttributes(prop, true);
Where prop is an object derived from the MemberInfo class that describes the property SomeProperty. Next you iterate through the returned attributes to see if it includes yours.

No, you can't. Not directly.
What you can do, at the moment you collect the attribute, is set that attribute with extra information:
class SomeAttr: Attribute
{
public PropertyInfo Target {get;set;}
}
... and when you have collected the information:
Type type = ... // The type which holds the property.
PropertyInfo propertyInfo = typeo.GetProperty("SomeProperty");
Type propertyType = propertyInfo.PropertyType;
SomeAttr attr = propertyInfo.GetCustomAttributes(false).OfType<SomeAttr>().FirstOrDefault();
attr.Target = propertyInfo; // <== Set the target information.
This way, you can always retrieve its target member at another point in your code:
public void DoSomethingWithAttribute(SomeAttr attr)
{
PropertyInfo whichProperty = attr.Target;
}
(You can also use the baseclass MemberInfo, to support methods, fields, etc.)

Related

c# Reflection, how to get generic type class properties

I have a Generic type List<Shift> where
public class Shift
{
[DisplayFormat(DataFormatString = "dd-MMM-yyy '(hours)'")]
public DateTimeOffset Date { get; set; }
[DisplayFormat(DataFormatString = "hh':'mm")]
public TimeSpan TimeWorked { get; set; }
}
I'm trying to get schedule props with attributes using reflection
var props = typeof(List<ShiftDayItem>).GetProperties();
var ShiftProperty = props.Last();
But ShiftProperty contains no attributes, so I can't access Date or TimeWorked.
Is reflection not aware of these or is there another way for me to get those properties?
Thanks!
I think you are misunderstanding what "Properties" are in c#.
Your Shift class has 2 properties: "Date" and "TimeWorked". To get info about these 2 properties you can simply write: typeof(Shift).GetProperties(). You are calling typeof(List<ShiftDayItem>).GetProperties() which will give you properties of List class: Count, Capacity, etc.. these are entirely unrelated.
I think you want to get attributes from Shift properties. To do this you need to get the generic parameter T from List<T>. To achive this you can do this
// Gets the generic type T from List<T>, in your case Shift
// Replace 'typeof(List<Shift>)' with your actual list
Type listType = typeof(List<Shift>).GenericTypeArguments[0];
To get all attributes from the type Shift you first need to get all the properites from which you can get the attributes.
// Gets all properties from the generic type T
PropertyInfo[] shiftProperties = listType.GetProperties();
Now that you have all the properties you can get the attributes
// Gets all Attributes from each property and puts them in one list (SelectMany)
IEnumerable<Attribute> attributes = shiftProperties.SelectMany(prop => prop.GetCustomAttributes());
You get IEnumerable<Attribute> from each property, which would result in IEnumerable<IEnumerable<Attribute>> which is not what we want. We used the method SelectMany which takes each IEnumerable and flattens it into one.
When you put everything together you get this
// Gets the generic type T from List<T>, in your case Shift
// Replace 'typeof(List<Shift>)' with your actual list
Type listType = typeof(List<Shift>).GenericTypeArguments[0];
// Gets all properties from the generic type T
PropertyInfo[] shiftProperties = listType.GetProperties();
// Gets all Attributes from each property and puts them in one list (SelectMany)
IEnumerable<Attribute> attributes = shiftProperties.SelectMany(prop => prop.GetCustomAttributes());
You need more code:
Dim shifttprops= ShiftProperty.PropertyType.GetProperties()
For Each prop in shifttprops
Dim attrs = prop.CustomAttributes
Next
Note the use of CustomAttributes instead of Attributes

Get a container class instance from a FieldInfo

I am working with C# reflection here:
I have a FieldInfo of a property and I would like to get the instance of the class it belong (so I can reach the content of another property):
for exemple take this class:
class MyClass
{
public int A { get; set; }
public int B { get; set; }
}
in some part of the code I have
void Function(FieldInfo fieldInfoOfA)
{
// here I need to find the value of B
}
Is this possible ?
Is this possible ?
No. Reflection is about discovery of the metadata of a type. A FieldInfo does not contain any information about a particular instance of that type. This is why you can get a FieldInfo without even creating an instance of the type at all:
typeof(MyClass).GetField(...)
Given the snippet above, you can see that a FieldInfo can be obtained without any dependence on a particular instance.
FieldInfo provides access to the metadata for a field within a class, it is independent of a specified instance.
If you have an instance of MyClass you can do this:
object Function(MyClass obj, FieldInfo fieldInfoOfA)
{
var declaringType = fieldInfoOfA.DeclaringType;
var fieldInfoOfB = declaringType.GetField("B");
return fieldInfoOfB.GetValue(obj);
}

ReflectedType of MemberExpression is the base class rather than actual class used

So I have a the following classes
class Person
{
virtual string Property{get;set;}
}
and
class Manager : Person
{
[SomeAttribute("Hello")]
override string Property {get;set;}
}
If I have a member expression on type Manager, ie:
Property prop = PropertyGetter.GetProp<Manager>(p => p.Property)
Then the ReflectedType of the MemberExpression is Person, rather than Manager. This means that the Attribute information is lost. So:
var attribute = prop.GetAttribute<SomeAttribute>();
Then attribute is null.
I'm assuming this is because the property is from the base class, not defined in Manager, but how can I get around this?
The issue is fixed if I use the new keyword on the property rather than virtual and override.
I think it has to do with the fact that there is no instance of the type Manager.
Another way to fix was to change my implementation of GetProp to do
return typeof(T).GetProperty(property.Name)
rather than just returning the property

Is it possible to get a property's private setter through reflection?

I wrote a custom serializer that works by setting object properties by reflection. Serializable classes are tagged with serializable attribute and all serializable properties are also tagged. For example, the following class is serializable:
[Serializable]
public class Foo
{
[SerializableProperty]
public string SomethingSerializable {get; set;}
public string SometthingNotSerializable {get; set;}
}
When the serializer is asked to deserialize SomethingSerializable, it gets the set method of the property and uses it to set it by doing something like this:
PropertyInfo propertyInfo; //the property info of the property to set
//...//
if (propertyInfo.CanWrite && propertyInfo.GetSetMethod() != null)
{
propertyInfo.GetSetMethod().Invoke(obj, new object[]{val});
}
This works fine, however, how can I make the property setter accessible only to the serializer? If the setter is private:
public string SomethingSerializable {get; private set;}
then the call to propertyInfo.GetSetMethod() returns null in the serializer. Is there any way to access the private setter or any other way to ensure that only the serializer can access the setter? The serializer is not guaranteed to be in the same assembly.
As you already figured out, one way to access a non-public setter is as follows:
PropertyInfo property = typeof(Type).GetProperty("Property");
property.DeclaringType.GetProperty("Property");
property.GetSetMethod(true).Invoke(obj, new object[] { value });
There is another way, though:
PropertyInfo property = typeof(Type).GetProperty("Property");
// if Property is defined by a base class of Type, SetValue throws
property = property.DeclaringType.GetProperty("Property");
property.SetValue(obj, value, BindingFlags.NonPublic | BindingFlags.Instance, null, null, null); // If the setter might be public, add the BindingFlags.Public flag.
Coming here from a search engine?
This question is specifically about accessing a non-public setter in a public property.
If both the property and setter are public, only the first example will work for you. To get the second example to work, you will need to add the BindingFlags.Public flag.
If the property is declared in a parent type and not visible to the type on which you're calling GetProperty, you won't be able to access it. You'll need to call GetProperty on a type to which the property is visible. (This doesn't affect private setters as long as the property itself is visible.)
If there are multiple declarations for the same property in the inheritance chain (via the new keyword), these examples will target the property that is immediately visible to the type on which GetProperty is called. For example, if class A declares Property using public int Property, and class B re-declares Property via public new int Property, typeof(B).GetProperty("Property") will return the property declared in B, while typeof(A).GetProperty("Property") will return the property declared in A.

c#, silverlight, check if field passed by ref has an attribute applied

In a base class I have the following method for derived classes:
protected virtual void SetValue<T>(ref T field, string propertyName, T value)
{
//assign value to the field and do some other staff
...
}
Is there any way to check if fieldVar has an attribute applied (for example DataMemberAttribute)?
No, there is no way to do that, except that it looks like you're also told the property name.
If you can find the FieldInfo of the field, then you can find any attributes, but not through the ref-parameter alone.
Reading between the lines you have a set of private fields which back the values of public properties. On some or all of these properties you some data attributes attached that you want to discover.
PropertyInfo pi = this.GetType().GetProperty(propertyName);
object[] dataMemberAttributes = pi.GetCustomAttributes(typeof(DataMemberAttribute, true);
if (dataMemberAttributes.Length > 0)
{
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)dataMemberAttributes[0];
// Do stuff with the attribute.
}

Categories