Suppose I have a class named Data.
Another class annotates one of its members, of type data, with some attribute.
For example:
public class Example{
[DefaultNameAttribute("default name")]
public Data Name{get;set}
}
What I'm looking for is a way, from within the class Data, to retrieve that attribute and the data it contains. I want to be able to write the following code:
public class Data{
private string _name = null;
public string Name{
get{
if (_name != null) return _name;
return (getDefaultNameFromAnnotation(this));//this is the method I'm looking for
}
}
In other words, I want to be able to give a default value to a specific field using custom attributes specified outside my class.
Short answer : You can't, or at least, you should not.
The DefaultNameAttribute is applied on a member of Example type, which is decorrelated from Data type. There could be several types that use Data type, and several instances of the DefaultNameAttribute. Example can even be defined in another assembly, etc.
It will depend on how your attribute is used (if it is on a class, property, method, etc...). For example if it is only used on a class you could get all types that are marked with your attribute with the following code:
public IEnumerable<Type> GetTypes(Assembly assembly)
{
foreach(Type type in assembly.GetTypes())
{
if (type.GetCustomAttributes(typeof(DefaultNameAttribute), true).Length > 0)
{
yield return type;
}
}
}
If it is only used on properties (as your example), then you could nest an additional foreach statement that will enumerate all properties for a given type and look for the attribute.
Related
I have an attribute that I am using to decorate object properties with. The attribute identifies the properties as needing validation to be performed on them. I am essentially implementing the Strategy Pattern and building all of the validation (really only about 6 types) in to individual objects that I can use across multiple classes. What I want to do, is provide parameters to the validation classes, without having to create an attribute for each validation object variation.
My attribute looks like this:
[AttributeUsage(AttributeTargets.Property)]
public class ValidationRuleAttribute : Attribute
{
public ValidationRuleAttribute(Type validationRule, string customFailureMessage = "")
{
if (typeof(IValidationRule).IsAssignableFrom(validationRule))
{
this.ValidationRule = string.IsNullOrEmpty(customFailureMessage)
? Activator.CreateInstance(validationRule, customFailureMessage) as IValidationRule
: Activator.CreateInstance(validationRule) as IValidationRule;
}
else
{
throw new ArgumentException(
string.Format(
"ValidationRule attributes can only be used with IValidationRule implementations. The '{0}' Tyoe is not supported.",
validationRule.Name));
}
}
public IValidationRule ValidationRule { get; private set; }
}
As an example, I have a simple StringIsNotNull validation object. I want to expand on it by allowing me to specify a minimum string length requirement. So the StringIsNotEmptyValidation would become StringHasMinimumLengthValidation
public class StringIsNotEmptyValidation : IValidationRule
{
private readonly string customErrorMessage;
public StringIsNotEmptyValidation()
{
}
public StringIsNotEmptyValidation(string customErrorMessage)
{
this.customErrorMessage = customErrorMessage;
}
public string ResultMessage { get; private set; }
public IValidationMessage Validate(System.Reflection.PropertyInfo property, IValidatable sender)
{
string value = property.GetValue(sender).ToString();
// Validate
bool isFailed = string.IsNullOrWhiteSpace(value);
if (isFailed)
{
if (string.IsNullOrEmpty(this.customErrorMessage))
{
DisplayNameAttribute displayName = property.GetCustomAttribute<DisplayNameAttribute>(true);
string errorMessage = displayName == null
? string.Format("You can not leave {0} empty.", property.Name)
: string.Format("You can not leave {0} empty.", displayName.DisplayName);
this.ResultMessage = errorMessage;
return new ValidationErrorMessage(errorMessage);
}
else
{
this.ResultMessage = this.customErrorMessage;
return new ValidationErrorMessage(customErrorMessage);
}
}
this.ResultMessage = string.Empty;
return null;
}
}
Within my model, I decorate my property with the attribute and validation object.
[RepositoryParameter(DbType.String)]
[ValidationRule(typeof(StringIsNotEmptyValidation))]
public string WorkDescription
{
get
{
return this.workDescription ?? string.Empty;
}
set
{
this.SetPropertyByReference(ref this.workDescription, value);
if (this.HasValidationMessageType<ValidationErrorMessage>(this.GetPropertyName(p => p.WorkDescription)))
{
this.Validate();
}
}
}
What I want to do, is write my attribute usage like this:
[ValidationRule(new StringIsNotEmptyValidation(minimumLength: 4))]
Since you can't instance objects in an attribute constructor, I'm forced to provide the attributes in my attribute constructor like this:
[ValidationRule(typeof(StringIsNotEmptyValidation), minLength: 4)]
I don't like this because if I have a ObjectIsNotNull or a StringIsInRange I will need to do two things:
Create a new attribute for each parameter variation (or a lot of overloads)
Set up the validation rule instances within the constructor, which will have varying property names.
The Validation object implements the following interface
public interface IValidationRule
{
string ResultMessage { get; }
IValidationMessage Validate(PropertyInfo property, IValidatable sender);
}
I don't want to bloat my interface with a large number of properties that might be used or might not be used depending on the Rule implementing it. It also makes it difficult to assign attribute params to the rule object.
So my question is how can I provide parameters to the IValidationRule concrete classes, without creating multiple attribute types to facilitate this? This is being used so that I an do cross-object validation. The PropertyInfo passed in to the validation rule is from a cache of PropertyInfo's. I need to keep the amount of reflection used down, otherwise I'd just use attributes for each rule parameter and use reflection on sender to figure out what ranges to use.
Update
After discussing this with Corey, it does indeed appear that attributes are supported in Universal Apps and it is only the DataAnnotations namespace that is missing. In order to get access to the attributes, I had to add a using statement to System.Reflection in order to gain access to a series of extension methods that expose the GetCustomAttribute methods. They are now extension methods and not built in to the Type class.
So I suppose in the end, I can just create my validation logic within the attributes, instead of individual objects. I can't think of any downsides to going this route.
In order to access the attributes in a Universal App, you have to include System.Reflection as a using statement, then access via the GetRuntimeProperties() extension method.
var validationRule = this
.GetType()
.GetRuntimeProperties() // Can be GetRuntimeFields or GetRuntimeMethods as well.
.FirstOrDefault(p => p.GetCustomAttribute<IntegerInRangeAttribute>() != null);
So there are a few options here.
First, and often used, is to have a different attribute for each type of rule you want to process. You are already building classes for each of your rules, so instead of having some encapsulating attribute that instantiates them all just make each rule an attribute:
[StringMinLengthRule(5)]
public string SomeString { get; set; }
Build the validation logic into your attributes - say with a base attribute that does the bulk of the work, calling a virtual method to do the actual validation. Then you can just enumerate the rule attributes and call them from your validation method.
Next, you can have a number of different properties on your attribute that can be set during declaration to provide the properties for your various rules:
[Validation(RuleType.StringMinLength, MinLength = 5)]
public string SomeString { get; set; }
You could still have the rules be processed in the ValidationAttribute itself, or create IValidationRule instances at run-time to process the actual validations. Unfortunately there's nothing to stop you from adding a Validation attribute that sets the wrong properties for the rule type, resulting in errors at run-time when you try to validate an instance.
Finally, something that works but probably shouldn't... and it's kinda ugly:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ValidationRuleAttribute : Attribute
{
public IValidationRule ValidationRule { get; private set; }
public ValidationRuleAttribute(RuleType type, params object[] parms)
{
if (type == RuleType.NotNull)
{
if (parms.Length != 0)
throw new ArgumentException("RuleType.NotNull requires 0 parameters", "parms");
ValidationRule = new NotNullValidation();
}
if (type == RuleType.StringMinLength)
{
if (parms.Length != 1)
throw new ArgumentException("RuleType.StringMinLength requires 1 parameter", "parms");
if (!(parms[0] is int))
throw new ArgumentException("RuleType.StringMinLength requires an integer", "parms");
ValidationRule = new StringLengthValidation((int)parms[0]);
}
}
}
The biggest problem with it is that it won't complain until you try to instantiate a class at run-time that has a bad Validation attribute. Your code can run quite happily up until the point where it tries to create an instance of that bad class, at which point all of the attributes will actually be constructed and those ArgumentExceptions start flying.
In fact only the first option doesn't suffer from run-time problems, because you can control the types of parameters being supplied by using the correct constructor formats. You can still tell it to do silly things - like requiring that strings must have less than 0 length for instance - but that's up to you :P
I have a C# class that is used in my custom DB ORM tools, called DbFieldAttribute.
I place it over my field, like so:
[DbField("User_Id")]
public int UserId{ get; set; }
Challenge: From my attributes Constructor code, get the FieldInfo of the field it is associated with the attribute. In the case above, it would give me the FieldInfo for UserId.
Any help would be great. Thanks.
Unfortunately, to the best of my knowledge, there is no way to accomplish what you are asking for.
But if it is not necessary that you get the PropertyInfo or the FieldInfo object inside your constructor, but instead you would be satisfied with it being passed to a method, then there is a possible solution.
First of all, your DbField class would need to be defined in the following way.
class DbField : Attribute
{
public DbField(string source) { }
public void GetInstance(PropertyInfo source)
{
Console.WriteLine(source.Name);
}
}
You would then need to define the following class which would get all the (in this case) properties marked with the DbField attribute, and pass them to the GetInstance(PropertyInfo) method.
class ActivateAttributes
{
public ActivateAttributes(object source)
{
source.GetType()
.GetProperties()
.Where(x => x.GetCustomAttributes().OfType<DbField>().Any())
.ToList()
.ForEach(x => (x.GetCustomAttributes().OfType<DbField>().First() as DbField).GetInstance(x));
}
}
The way you would trigger this process is inside an abstract class, which is defined as so.
abstract class AbstractDecoratedClass
{
public AbstractDecoratedClass()
{
new ActivateAttributes(this);
}
}
Now your target class, which has its properties decorated by DbField attributes, simply needs to derive from this class, so that you won't be bothered by the invocation inside the constructor.
class DecoratedClass : AbstractDecoratedClass
{
[DbField("User_Id")]
public int UserId { get; set; }
[DbField("User_Id2")]
public int UserId2 { get; set; }
}
You are now only left with testing the solution as shown here.
class Program
{
static void Main()
{
new DecoratedClass();
Console.Read();
}
}
The solution could not be solved directly, as #Mario pointed out, but here is the solution I ended up going with.
The key is to know that the attribute alone has no way of knowing this information, but at the time it is called it is reasonable to expect that the FieldInfo or PropertyInfo was also available.
My original problem was that my ORM code looked to an attribute to determine if a field/property related to a database field. Then, I had instances where the Prop/Field name in the class did not match up with the database for reasons of making it more logical to the Code/Db. In those cases I needed to pass in a field name to use instead of the actual field. I was hoping the attribute could do more of the work, or at least help make it more obvious for any future code that used it.
(I stripped out xml comments and extra code not relavant to this solution)
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class DbFieldAttribute : Attribute
{
private string fieldName = "";
public DbFieldAttribute() { }
public DbFieldAttribute(string fieldName)
{
this.fieldName = fieldName;
}
public string FieldName(PropertyInfo pi)
{
if (this.fieldName != "") return this.fieldName;
else return pi.Name;
}
public string FieldName(FieldInfo fi)
{
if (this.fieldName != "") return this.fieldName;
else return fi.Name;
}
Now when my ORM code wants the field name, it has to pass in the field or property info related to that field. This means that what is needed, is now intrinsic in the attributes use, instead of needing to be derived in external code.
MSDN states of the property TypeId that:
As implemented, this identifier is merely the Type of the attribute. However, it is intended that the unique identifier be used to identify two attributes of the same type.
Is the intended use however, to distinguish between individual attribute instances (e.g. those associated with different instances of the class to which they are applied) or between attributes which have the same type but due to their property values are semantically different?
For example, say I had the following:
public sealed class AmpVolume : System.Attribute
{
public int MaxVolume { get; set; }
public AmpVolume(int maxvolume)
{
MaxVolume = maxvolume;
}
}
[AmpVolume(11)]
public class SpinalTapGuitarAmp
{
}
[AmpVolume(11)]
public class SpinalTapBassAmp
{
}
[AmpVolume(10)]
public class RegularAmp
{
}
Should I implement TypeId as
get
{
return (object)this; //TypeId identifies every individual instance of the attribute
}
Or
get
{
return (object)MaxVolume; //If we compare two AmpVolume attributes, they should be the same if the volume is the same, right?
}
The TypeId property is used to distinguish between instances of the same attribute on the same member. Meaning, it's required to implement it only when the attribute is decorated with AttributeUsageAttribute which declares AllowMultiple=true.
For example, if you'd decorate a class or method with multiple AmpVolume attributes, then the TypeId will distinguish between those instances.
You can find a hint on the property in the note at this MSDN link for GetAttributes method.
In C#, I am defining a static field of a specific class. From within the class, I want to be able to display the name of the static field, pretty much like this:
public class Unit {
public string NameOfField { get { return ...; } }
}
public static Unit Hectare = new Unit();
If I now access:
Hectare.NameOfField
I want it to return:
Hectare
I know there is a static function System.Reflection.MethodBase.GetCurrentMethod(), but as far as I can tell there is no way to get the name of the instance containing this current method?
There is also the System.RuntimeFieldHandle structure, but I have not been able to identify any GetCurrentFieldHandle() method.
I am not sure if I am missing something obvious?
Any help on this is very much appreciated.
You should not count on variable names in you developments as they do not exits at runtime.
It's better to initialize Unit with a name directly:
public class Unit {
public Unit(string name)
{
NameOfField = name;
}
public string NameOfField { get; private set;} }
}
public static Unit Hectare = new Unit("Hectare");
Only way around this will be to store that information in the class:
public static Unit Hectare = new Unit("Hectare");
When your code is compiled all variable names are lost and replaced by internal references. There is no way to get that name again.
You can use Reflection to obtain class Fields and properties. Like below:
Suppose you have class with one property:
class Test
{
public static string MySupperField
{
get
{
return "Some symbols here";
}
}
}
......
You can read the property name in such way:
public string[] GetClassStaticNames(Type T)
{
string[] names;
System.Reflection.PropertyInfo[] props = T.GetProperties(); // This will return only properties not fields! For fields obtaining use T.GetFields();
names = new string[props.Count()];
for (int i = 0; i < props.Count(); i++)
{
names[i] = props[i].Name;
}
return names;
}
Hope this will help.
[EDIT]
Returning to your question - No you cant obtain name of current variable.
What you are asking about cant be done because of classes nature, they are objects in memory and reference to one object can be held in many variables, and when you are requesting value of instance field or property it will be actually performed operation with object in memory not with variable wich holds reference to that object. So obtaining name of variable wich holds reference to current instance have no sence
Thanks everyone who has taken the time to answer and discuss my question.
Just to let you know, I have implemented a solution that is sufficient for my needs. The solution is not general, and it has some pitfalls, but I'd thought I share it anyway in case it can be of help to someone else.
This is in principle what the class that is used when defining fields looks like:
public class Unit : IUnit {
public NameOfField { get; set; }
...
}
As you can see, the class implements the IUnit interface, and I have provided a public setter in the NameOfField property.
The static fields are typically defined like this within some containing class:
public static Unit Hectare = new Unit();
My solution is to set the NameOfField property through reflection before the field is used in the implementation.
I do this through a static constructor (that of course needs to be invoked before the Unit fields are accessed.
I use Linq to traverse the executing assembly for the relevant fields, and when I have detected these fields (fields which type implements the IUnit interface), I set the NameOfField property for each of them using the Any extension method:
Assembly.GetExecutingAssembly().GetTypes().
SelectMany(type => type.GetFields(BindingFlags.Public | BindingFlags.Static)).
Where(fieldInfo => fieldInfo.FieldType.GetInterfaces().Contains(typeof(IUnit))).
Any(fieldInfo =>
{
((IUnit)fieldInfo.GetValue(null)).NameOfField= fieldInfo.Name;
return false;
});
There are some shortcomings with this approach:
The static constructor has to be invoked through manual intervention before any Unit fields can be accessed
The NameOfField setter is public. In my case this is no problem, but it might be when applied in other scenarios. (I assume that the setter could be made private and invoked through further reflection, but I have not taken the time to explore that path further.)
... ?
Either way, maybe this solution can be of help to someone else than me.
Today, I was cleaning up some of my code with FXCop and it complained about a Attribute class I had with this violation.
CA1019: Define accessor for attribute argument.
On this page, http://msdn.microsoft.com/en-us/library/ms182136.aspx there is more information, but I still do not get the reason for this as it seems to me more verbose and less relevant.
It gives two codes samples.
using System;
namespace DesignLibrary
{
// Violates rule: DefineAccessorsForAttributeArguments.
[AttributeUsage(AttributeTargets.All)]
public sealed class BadCustomAttribute :Attribute
{
string data;
// Missing the property that corresponds to
// the someStringData parameter.
public BadCustomAttribute(string someStringData)
{
data = someStringData;
}
}
// Satisfies rule: Attributes should have accessors for all arguments.
[AttributeUsage(AttributeTargets.All)]
public sealed class GoodCustomAttribute :Attribute
{
string data;
public GoodCustomAttribute(string someStringData)
{
data = someStringData;
}
//The constructor parameter and property
//name are the same except for case.
public string SomeStringData
{
get
{
return data;
}
}
}
}
I don't understand why the SomeStringData property is required. Isn't the someStringData a parameter? Why does it need to have its own property if it is already stored in another property?
Actually, mine is a little different as it looks like this.
[AttributeUsage(AttributeTargets.Property)]
public sealed class ExampleAttribute : Attribute
{
public ExampleAttribute(string attributeValue)
{
this.Path = attributeValue;
}
public string Name
{
get;
set;
}
// Add to add this to stop the CA1019 moaning but I find it useless and stupid?
public string AttributeValue
{
get
{
return this.Name;
}
}
}
Rather than a private field, I have used a public autoproperty, I had to add the last part to make the warning stop but I don't see the point and it also adds another public field to this class, which is redundant, and seems less clean.
That said, I assume that this warning is raised for a reason so what good reason I am missing here?
Thanks in advance.
FxCop is complaining because your existing property doesn't match the parameter name.
Therefore, it doesn't realize that the parameter actually is exposed.
You should rename the property or parameter to match (except for case), or suppress the warning.
FxCop rule CA1019 is just enforcing the .Net Framework coding guidelines for Attributes.
Use named arguments (read/write properties) for optional parameters. Provide a read/write property with the same name as each named argument, but change the case to differentiate between them.
Documentation Link: http://msdn.microsoft.com/en-us/library/2ab31zeh(v=vs.71).aspx
The reason behind the FxCop warning is that every piece of data you pass into the attribute's constructor should be made publicly available to access when the attribute instance is being retrieved by Reflection.
Let's say you have this:
[BadCustom("My String Data")]
public class DecoratedClass
{
}
How will you get "My String Data" back from that attribute instance when you read it using:
BadCustomAttribute attr = typeof(DecoratedClass)
.GetCustomAttributes(typeof(BadCustomAttribute), false)
.Single() as BadCustomAttribute;
Now you have the instance of your attribute, but no way to read the string passed into the constructor because you didn't at least declare a read-only property for it.
the idea is that you should write just:
[AttributeUsage(AttributeTargets.Property)]
public sealed class ExampleAttribute : Attribute
{
public ExampleAttribute(string attributeValue)
{
this.AttributeValue = attributeValue;
}
public string AttributeValue
{
get;
set;
}
}
This violation will also be thrown when the parameter name matches the property name, but the data types are different.