GetCustomAttributes does not return value - c#

I have defined a custom attribute
[AttributeUsage(AttributeTargets.Property )]
public class FieldAttribute: Attribute
{
public FieldAttribute(string field)
{
this.field = field;
}
private string field;
public string Field
{
get { return field; }
}
}
My Class which uses the custom attribute is as below
[Serializable()]
public class DocumentMaster : DomainBase
{
[Field("DOC_CODE")]
public string DocumentCode { get; set; }
[Field("DOC_NAME")]
public string DocumentName { get; set; }
[Field("REMARKS")]
public string Remarks { get; set; }
}
}
But when i try to get the value of the custom attribute it returns null object
Type typeOfT = typeof(T);
T obj = Activator.CreateInstance<T>();
PropertyInfo[] propInfo = typeOfT.GetProperties();
foreach (PropertyInfo property in propInfo)
{
object[] colName = roperty.GetCustomAttributes(typeof(FieldAttributes), false);
/// colName has no values.
}
What am I missing?

typo: should be typeof(FieldAttribute). There is an unrelated system enum called FieldAttributes (in System.Reflection, which you have in your using directives, since PropertyInfo resolves correctly).
Also, this is easier usage (assuming the attribute doesn't allow duplicates):
var field = (FieldAttribute) Attribute.GetCustomAttribute(
property, typeof (FieldAttribute), false);
if(field != null) {
Console.WriteLine(field.Field);
}

Related

How can I get the value of specific key inside a model dynamically?

I have here my model:
public class RoleModel
{
public int ID { get; set; }
public string RoleName { get; set; }
public UserRoleModel TrackAndTrace { get; set; }
public UserRoleModel MailDelivery { get; set; }
public UserRoleModel MailAccounting { get; set; }
public UserRoleModel PerformanceMonitoring { get; set; }
public UserRoleModel AdminSettings { get; set; }
}
I want to get the value of any key of 'RoleModel'
public bool SaveRoleModule(RoleModel role)
{
PropertyInfo[] properties = typeof(RoleModel).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name != "ID" && property.Name != "RoleName")
{
Console.WriteLine(role[property.Name]);//(this doesn't work) I want it dynamic
Console.WriteLine(role.TrackAndTrace); //not like this
}
}
return true;
}
I used loop to shorten my code.
You can use this method here: Get property value from string using reflection in C# like this:
public bool SaveRoleModule(RoleModel role)
{
PropertyInfo[] properties = typeof(RoleModel).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name != "ID" && property.Name != "RoleName")
{
var value = GetPropValue(role, property.Name);
Console.WriteLine(value);//(this doesn't work) I want it dynamic
Console.WriteLine(role.TrackAndTrace); //not like this
}
}
return true;
}
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
You could try something like this:
public bool SaveRoleModule(RoleModel role)
{
PropertyInfo[] properties = typeof(RoleModel).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name != "ID" && property.Name != "RoleName")
{
Type t = role.GetType();
PropertyInfo p = t.GetProperty(property.Name);
UserRoleModel urm = ((UserRoleModel)p.GetValue(role, null));
// do something with urm
}
}
return true;
}
Though Fabio is right, this does seem strange and potentially based on faulty reasoning.

c# Reflection - Accessing object properties on static class

I used code from this post to implement feature toggles in an application and it is working great. However, now instead of my features being a straight bool on/off, each feature has two bool values: one for the general setting and one for the setting which is only applied to a subset of users. I've been trying to update the code to handle this and I'm finding my basic understanding of reflection and accessors is coming up short.
I'm using the code below to test in LINQPad - basically, compared to the post mentioned above, all I've done is tried to change TestFeatureToggle from a bool, to type MultiToggle but I'm struggling to Set or Get the value of the bool properties of the MultiToggle object. I get an exception at
return (bool)multiToggleProperty.GetValue(null,null);
"Non-static method requires a target". Which makes sense because the properties on MultiToggle are non-static. However, I don't have an instance of those objects and I don't understand how I would get one from a static class.
Any help would be really appreciated. My gut says it might not be possible!
void Main()
{
var exampleFeatureToggles = new List<FeatureToggle>
{
new FeatureToggle {Description = "Test", Id = 1, IsActive = true, Name = "TestFeatureToggle"}
};
FeatureToggles.SetFeatureToggles(exampleFeatureToggles);
Console.WriteLine(FeatureToggles.GetFeatureToggleSetting("TestFeatureToggle"));
}
public class FeatureToggle
{
public string Description { get; set; }
public int Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
}
public class MultiToggle
{
public bool DefaultValue { get; private set; }
public bool OtherValue { get; private set; }
}
public static class FeatureToggles
{
//public static bool TestFeatureToggle { get; private set; }
public static MultiToggle TestFeatureToggle { get; private set; }
public static void SetFeatureToggles(List<FeatureToggle> toggles)
{
if (toggles == null) return;
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static);
// All properties must be set to false to prevent a property staying true when deleted from the database
foreach (var property in properties)
{
var multiToggleProperties = typeof(MultiToggle).GetProperties();
foreach (var multiToggleProperty in multiToggleProperties)
{
multiToggleProperty.SetValue(new MultiToggle(), false, null);
}
}
foreach (var toggle in toggles)
{
foreach (var property in properties)
{
if (property.Name.ToLower() == toggle.Name.ToLower())
{
Type tProp = property.GetType();
var multiToggleProperties = typeof(MultiToggle).GetProperties();
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
multiToggleProperty.SetValue(new MultiToggle(), toggle.IsActive, null);
}
}
}
}
}
public static bool GetFeatureToggleSetting(string propertyName)
{
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (var property in properties)
{
if (property.Name.ToLower() == propertyName.ToLower())
{
Type tProp = property.GetType();
var multiToggleProperties = typeof(MultiToggle).GetProperties();
Console.WriteLine(multiToggleProperties);
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
return (bool)multiToggleProperty.GetValue(null, null);
}
}
}
return false;
}
}
The idea was there but you've essentially "just overshot the mark". You are getting the "Non-static method requires a target" error because you are trying to get the value of a property in the value of a static property, without getting the value of the static property first (what a mouthful). i.e. you are going:
get static property type -> get instance property type -> get value of property from static property.
DefaultValue, and OtherValue are instance properties so you will need the instance object first before you can get their value. I made a few tweaks just to show you how to both set the static property and get the values from the static property. You should be able to tweak it from there:
void Main()
{
var exampleFeatureToggles = new List<FeatureToggle>
{
new FeatureToggle {Description = "Test", Id = 1, IsActive = true, Name = "TestFeatureToggle"}
};
FeatureToggles.SetFeatureToggles(exampleFeatureToggles);
Console.WriteLine(FeatureToggles.GetFeatureToggleSetting("TestFeatureToggle"));
}
public class FeatureToggle
{
public string Description { get; set; }
public int Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
}
public class MultiToggle
{
public bool DefaultValue { get; private set; }
public bool OtherValue { get; private set; }
}
public static class FeatureToggles
{
//public static bool TestFeatureToggle { get; private set; }
public static MultiToggle TestFeatureToggle { get; private set; }
public static void SetFeatureToggles(List<FeatureToggle> toggles)
{
if (toggles == null) return;
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static);
// All properties must be set to false to prevent a property staying true when deleted from the database
foreach (var property in properties)
{
// first change: set the _property_, not multiToggleProperty
property.SetValue(null, new MultiToggle());
}
foreach (var toggle in toggles)
{
foreach (var property in properties)
{
if (property.Name.ToLower() == toggle.Name.ToLower())
{
Type tProp = property.GetType();
var multiToggleProperties = typeof(MultiToggle).GetProperties();
// second change: create a nee instance, set the values, then set that value on the static property
var newMultiToggle = new MultiToggle();
property.SetValue(null, newMultiToggle);
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
multiToggleProperty.SetValue(newMultiToggle, toggle.IsActive, null);
}
}
}
}
}
public static bool GetFeatureToggleSetting(string propertyName)
{
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
foreach (var property in properties)
{
if (property.Name.ToLower() == propertyName.ToLower())
{
Type tProp = property.GetType();
// third change: get the static value first, then get the value from the properties on that instance.
var value = property.GetValue(null);
var multiToggleProperties = typeof(MultiToggle).GetProperties();
Console.WriteLine(multiToggleProperties);
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
return (bool)multiToggleProperty.GetValue(value, null); //
}
}
}
return false;
}
}

Read override property attribute

I have overridden property in class and would like to read custom attribute values, but it do not work. Could anyone explain why it is not working and how to solve the problem?
public class Validator
{
[Serializable]
public class CollectionAttribute : Attribute
{
public virtual string[] Data { get; set; }
public string Default;
}
}
class Helpers
{
public static MemberInfo GetMemberInfo<T, TU>(Expression<Func<T, TU>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null)
return member.Member;
throw new ArgumentException("Expression is not a member access", "expression");
}
public static string GetName<T, TU>(Expression<Func<T, TU>> expression)
{
return GetMemberInfo(expression).Name;
}
public static string GetCollection<T, TU>(Expression<Func<T, TU>> expression)
{
var attribute = (Validator.CollectionAttribute[])GetMemberInfo(expression).GetCustomAttributes(typeof(Validator.CollectionAttribute), true);
return string.Join(",", attribute[0].Data);
}
}
Do not work.
public class TestClass:TestBaseClass
{
[Validator.Collection(Data = new[] { "doc", "docx", "dot", "dotx", "wpd", "wps", "wri" })]
public override string InputFormat { get; set; }
}
public class TestBaseClass
{
public virtual string InputFormat { get; set; }
}
Helpers.GetCollection((TestClass p) => p.InputFormat)
//The attribute variable in GetCollection method always null. It seems code looks for atribute in Base class.
Works fine.
public class TestClass
{
[Validator.Collection(Data = new[] { "doc", "docx", "dot", "dotx", "wpd", "wps", "wri" })]
public override string InputFormat { get; set; }
}
Helpers.GetCollection((TestClass p) => p.InputFormat)
The declaring type of InputFormat is TestBaseClass which doesn't have that attribute. And the PropertyInfo which returned is for the declaring type, not for the actual type of the parameter.
What you have to do, is retrieve the actual type of the expression's parameter, and then return the PropertyInfo for that type.
public static MemberInfo GetMemberInfo<T, TU>(Expression<Func<T, TU>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null)
{
// Getting the parameter's actual type, and retrieving the PropertyInfo for that type.
return expression.Parameters.First().Type.GetProperty(member.Member.Name);
}
throw new ArgumentException("Expression is not a member access", "expression");
}

Get Custom Attributes Generic

I am creating a custom attribute. And I will use it in multiple classes:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class Display : System.Attribute
{
public string Name { get; set; }
public string Internal { get; set; }
}
public class Class1
{
[Display(Name = "ID")]
public int ID { get; set; }
[Display(Name = "Name")]
public string Title { get; set; }
}
public class Class2
{
[Display(Name = "ID")]
public int ID { get; set; }
[Display(Name = "Name")]
public string Title { get; set; }
}
Here is working correctly but I want to make it as generic as possible, like the MVC example:
Class1 class1 = new Class1();
class1.Title.DisplayName () / / returns the value "Name"
The only thing I could do was generate a loop of my property, but I need to inform my typeof Class1
foreach (var prop in typeof(Class1).GetProperties())
{
var attrs = (Display[])prop.GetCustomAttributes(typeof(Display), false);
foreach (var attr in attrs)
{
Console.WriteLine("{0}: {1}", prop.Name, attr.Name);
}
}
Is there any way to do it the way I want?
You can't do what you've shown exactly because class1.Title is an expression that evaluates to a string. You are looking for metadata about the Title property. You can use Expression Trees to let you write something close. Here's a short helper class that pulls the attribute value out of a property in an expression tree:
public static class PropertyHelper
{
public static string GetDisplayName<T>(Expression<Func<T, object>> propertyExpression)
{
Expression expression;
if (propertyExpression.Body.NodeType == ExpressionType.Convert)
{
expression = ((UnaryExpression)propertyExpression.Body).Operand;
}
else
{
expression = propertyExpression.Body;
}
if (expression.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("Must be a property expression.", "propertyExpression");
}
var me = (MemberExpression)expression;
var member = me.Member;
var att = member.GetCustomAttributes(typeof(DisplayAttribute), false).OfType<DisplayAttribute>().FirstOrDefault();
if (att != null)
{
return att.Name;
}
else
{
// No attribute found, just use the actual name.
return member.Name;
}
}
public static string GetDisplayName<T>(this T target, Expression<Func<T, object>> propertyExpression)
{
return GetDisplayName<T>(propertyExpression);
}
}
And here's some sample usage. Note that you really don't even need an instance to get this metadata, but I have included an extension method that may be convenient.
public static void Main(string[] args)
{
Class1 class1 = new Class1();
Console.WriteLine(class1.GetDisplayName(c => c.Title));
Console.WriteLine(PropertyHelper.GetDisplayName<Class1>(c => c.Title));
}

Recursively Get Properties & Child Properties Of An Object

Ok so at first I thought this was easy enough, and maybe it is and I'm just too tired - but here's what I'm trying to do. Say I have the following objects:
public class Container
{
public string Name { get; set; }
public List<Address> Addresses { get; set; }
}
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public List<Telephone> Telephones { get; set; }
}
public class Telephone
{
public string CellPhone { get; set; }
}
What I need to be able to do, is 'flatten' Containers property names in to a string (including ALL child properties AND child properties of child properties) that would look something like this:
Container.Name, Container.Addresses.AddressLine1, Container.Addresses.AddressLine2, Container.Addresses.Telephones.CellPhone
Does that make any sense? I can't seem to wrap it around my head.
I suggest you to mark all the classes, you need to grab, with custom attribute after that you could do something like this
class Program
{
static void Main(string[] args)
{
var lines = ExtractHelper.IterateProps(typeof(Container)).ToArray();
foreach (var line in lines)
Console.WriteLine(line);
Console.ReadLine();
}
}
static class ExtractHelper
{
public static IEnumerable<string> IterateProps(Type baseType)
{
return IteratePropsInner(baseType, baseType.Name);
}
private static IEnumerable<string> IteratePropsInner(Type baseType, string baseName)
{
var props = baseType.GetProperties();
foreach (var property in props)
{
var name = property.Name;
var type = ListArgumentOrSelf(property.PropertyType);
if (IsMarked(type))
foreach (var info in IteratePropsInner(type, name))
yield return string.Format("{0}.{1}", baseName, info);
else
yield return string.Format("{0}.{1}", baseName, property.Name);
}
}
static bool IsMarked(Type type)
{
return type.GetCustomAttributes(typeof(ExtractNameAttribute), true).Any();
}
public static Type ListArgumentOrSelf(Type type)
{
if (!type.IsGenericType)
return type;
if (type.GetGenericTypeDefinition() != typeof(List<>))
throw new Exception("Only List<T> are allowed");
return type.GetGenericArguments()[0];
}
}
[ExtractName]
public class Container
{
public string Name { get; set; }
public List<Address> Addresses { get; set; }
}
[ExtractName]
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public List<Telephone> Telephones { get; set; }
}
[ExtractName]
public class Telephone
{
public string CellPhone { get; set; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)]
public sealed class ExtractNameAttribute : Attribute
{ }
Per my comment, you could use something like this if it will always be a generic List type that you want to link to a child type. IteratePropertiesRecursively is an iterator over the properties of the given type, that will recursively enumerate the properties of the type and all child types linked through a generic List.
protected void Test()
{
Type t = typeof(Container);
string propertyList = string.Join(",", IteratePropertiesRecursively("", t).ToArray<string>());
// do something with propertyList
}
protected IEnumerable<string> IteratePropertiesRecursively(string prefix, Type t)
{
if (!string.IsNullOrEmpty(prefix) && !prefix.EndsWith(".")) prefix += ".";
prefix += t.Name + ".";
// enumerate the properties of the type
foreach (PropertyInfo p in t.GetProperties())
{
Type pt = p.PropertyType;
// if property is a generic list
if (pt.Name == "List`1")
{
Type genericType = pt.GetGenericArguments()[0];
// then enumerate the generic subtype
foreach (string propertyName in IteratePropertiesRecursively(prefix, genericType))
{
yield return propertyName;
}
}
else
{
// otherwise enumerate the property prepended with the prefix
yield return prefix + p.Name;
}
}
}
Note: This code will not correctly handle a type that recursively includes itself as a type of one of its properties. Trying to iterate over such a type will result in a StackOverflowException, as pointed out by #Dementic (thanks!).

Categories

Resources