Run time attributes in C#
So, what are attributes in c#?
"Attributes provide a powerful method of associating declarative information with C# code (types, methods, properties, and so forth). Once associated with a program entity, the attribute can be queried at run time and used in any number of way" - MSDN.
Also attributes are classes that inherits System.Attribute as below
public class UIAttributes : Attribute
{
private bool isReadOnly = false;
public bool IsReadOnly
{
get { return isReadOnly; }
}
public UIAttributes(bool isReadOnly)
{
this.IsReadOnly = isReadOnly;
}
}
public class ProductViewData
{
public string Name { get; set; }
[UIAttributes(true)] //ProdcutID property is decorated to be read only.
public int ProductID { get; set; }
public double Price { get; set; }
}
{
PropertyInfo[] propInfo = o.GetType().GetProperties();
foreach(PropertyInfo prop in propInfo)
{
foreach(Attribute att in prop.GetCustomAttributes(true))
{
if((att is UIAttributes) && (((UIAttributes)att).IsReadOnly) )
{
//Do somthing.
}
}
}
}
Interface:
public interface IUIAttributes
{
bool IsReadOnly(string PName);
bool IsReadOnly();
}
Custom Attribute:
[AttributeUsage(AttributeTargets.Property)]
public class UIAttributes : Attribute
{
private bool isReadOnly = false;
public bool IsReadOnly
{
get { return isReadOnly; }
set { isReadOnly = value; }
}
public UIAttributes()
{
}
{
this.IsReadOnly = isReadOnly;
}
}
public class ProductViewData : IUIAttributes
{
public string Name { get; set; }
public int ProductID { get; set; }
public double Price { get; set; }
#region IUIAttributes Members
bool IUIAttributes.IsReadOnly(string PName)
{
if (PName.Equals("ProductID"))
return true;
else
return false;
}
{
return false;
}
}
Now I have to write a CustomTypeDescriptor and Provider, this descriptor will create instances of my custom attribute UIAttribute and associate them to types that implement the Interface:
public sealed class CustomTypeDescriptionProvider
{
///
/// Constructor
///
public CustomTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{
}
///
/// Create and return a custom type descriptor and chains it with the original
/// custom type descriptor
///
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new UIAttributeCustomTypeDescriptor
}
}
public sealed class UIAttributeCustomTypeDescriptor
{
///
/// Constructor
///
public UIAttributeCustomTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent)
{
}
public override AttributeCollection GetAttributes()
{
Type UIType = typeof(T).GetInterface(typeof(IUIAttributes).Name);
if (UIType != null)
{
IUIAttributes UIInstance = GetPropertyOwner(base.GetProperties().Cast<PropertyDescriptor>().First()) as IUIAttributes;
bool instanceLevelRoles = UIInstance.IsReadOnly();
List<Attribute> attributes = new List<Attribute>(base.GetAttributes().Cast<Attribute>());
UIAttributes UIAttrib = new UIAttributes(instanceLevelRoles);
TypeDescriptor.AddAttributes(UIInstance, UIAttrib);
attributes.Add(UIAttrib);
return new AttributeCollection(attributes.ToArray());
}
return base.GetAttributes();
}
///
/// This method add a new property to the original collection
///
public override PropertyDescriptorCollection GetProperties()
{
// Enumerate the original set of properties and create our new set with it
PropertyDescriptorCollection originalProperties = base.GetProperties();
List<PropertyDescriptor> newProperties = new List<PropertyDescriptor>();
Type UIType = typeof(T).GetInterface("IUIAttributes");
if (UIType != null)
{
foreach (PropertyDescriptor pd in originalProperties)
{
IUIAttributes UIInstance = GetPropertyOwner(pd) as IUIAttributes;
bool propertyIsReadOnly = UIInstance.IsReadOnly(pd.Name);
UIAttributes UIAttrib = new UIAttributes(propertyIsReadOnly);
// Create a new property and add it to the collection
PropertyDescriptor newProperty = TypeDescriptor.CreateProperty(typeof(T), pd.Name, pd.PropertyType, UIAttrib);
newProperties.Add(newProperty);
}
// Finally return the list
return new PropertyDescriptorCollection(newProperties.ToArray(), true);
}
return base.GetProperties();
}
}
I have overridden GetAttributes in which I query the underlying instance to get read-only mode of the instance. Similarly, I have also overridden GetProperties which will in turn query the instance to get read-only mode of the specified property name.
We are now ready to associate the UIAttribute with our class instances.
pvd.ProductID = 1;
pvd.Name = "Product1";
pvd.Price = 99.99;
TypeDescriptor.AddProvider(new CustomTypeDescriptionProvider<ProductViewData>(TypeDescriptor.GetProvider(typeof(ProductViewData))),pvd);
And then by Reflection we can get properties attributes and check its layout behavior without knowing instance type, in next piece of code ‘Model’ is the instance name and ‘Name’ is the property name.
{
bool readonlyatt = false;
UIAttributes uiatt = TypeDescriptor.GetAttributes(Model).Cast<Attribute>().SingleOrDefault(a => a.GetType().Name == typeof(UIAttributes).Name) as UIAttributes;
if ((uiatt != null) && uiatt.IsReadOnly)
return uiatt.IsReadOnly;
PropertyInfo propInfo = Model.GetType().GetProperty(Name);
//(propInfo =>
{
PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(Model).Cast<PropertyDescriptor>().SingleOrDefault(p => propInfo.Name == p.Name);
if (propDescriptor != null)
{
UIAttributes attrib = propDescriptor.Attributes.Cast<Attribute>().SingleOrDefault(p => p.GetType().Name == typeof(UIAttributes).Name) as UIAttributes;
if (attrib != null)
{
readonlyatt = attrib.IsReadOnly;
}
}
}
//);
return readonlyatt;
}
ana mesh fahma 7aga but this looks so great :D especially the code snippets :D i hope i will understand one day :D lol
ReplyDelete