I understand that they are compile time, so they can't be generic, and must be initialized with constant values. But:
Why can't they have information you would get if you reflected whatever they are being applied to?
Why can't they accept lambda expressions, functions, or delegates? Aren't functions constant to the compiler?
Attributes could be a phenomenally powerful declarative tool if just one of the above were true, instead they are more like comments that can be read through reflection.
This was sort of a rant, but I really want to know why they seem like such a half assed feature.
Here is what I wanted to do. It was supposed to be an api for mapping values from resources through the function given to the attribute to the property the attribute is applied to. Note that the abstract class wouldn't have to exist if Attributes could know what they are reflecting. I'm posting this because someone wanted to know why I would want to give functions to attribute constructors, and maybe because what I'm trying to do has already been done.
public delegate void PropertyHandler(object parent, PropertyInfo property, object value);
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FromResourceAttribute : Attribute
{
private static readonly PropertyHandler m_defaultHandler = (parent, property, value) =>
{
property.SetValue(parent, value, null);
};
public PropertyHandler Handler { get; set; }
public FromResourceAttribute(PropertyHandler handler)
{
Handler = handler;
}
public FromResourceAttribute()
{
Handler = m_defaultHandler;
}
}
public abstract class ResourceDependent
{
public ResourceDependent(ResourceManager resources)
{
var resourceDependentProperties =
from property in GetType().GetProperties()
let fromResourceAttributes = property.GetCustomAttributes(typeof(FromResourceAttribute), true)
where fromResourceAttributes.Count() == 1
let propertyHandler = ((FromResourceAttribute)fromResourceAttributes.Single()).Handler
select new { Info = property, Handler = propertyHandler };
foreach(var property in resourceDependentProperties)
{
property.Handler(this, property.Info, resources.GetObject(property.Info.Name));
}
}
}
class ResourceDependentTest : ResourceDependent
{
[FromResource]
public string Data { get; set; }
[FromResource((parent, property, value) => property.SetValue(parent, ((string)value).Split('|'), null))]
public string[] Data2 { get; set; }
static PropertyHandler Data3Handler = (parent, property, value) =>
{
//Magic
};
[FromResource(Data3Handler)]
public int Data3 { get; set; }
public ResourceDependentTest() : base(Properties.Resources.ResourceManager)
{
}
}