I have produced a custom attribute which simply marks a classes property as being the 'display name'. What I would like to do is find the property within a given class which has been marked with my attribute. As far as I know, the only way I can do this is to loop through each property (via reflection) and check what attributes it has assigned. Is there any easier/quicker way than this?
foreach (PropertyInfo property in myClassProperties)
{
//Get the alias attributes.
object[] attr=
property.GetCustomAttributes(typeof(DisplayField), true);
if(attr.Count() > 0)
{
// This is a display field!
}
}
Thanks
Well, it's slightly simpler than checking all its attributes to find the one you want - you can ask any member whether it has a particular attribute using IsDefined:
var properties = type.GetProperties()
.Where(p => p.IsDefined(typeof(MyAttribute), false));
Obviously you can cache that result on a per-type basis if you're going to use it multiple times.
As far as I know, the only way I can do this is to loop through each property (via reflection) and check what attributes it has assigned.
That's exactly the way to do it. Attributes are metadata which is baked into the assembly at compile time. In order to access them at runtime you need Reflection.
the only quicker way that I'm aware of is to create a dictionary either statically or in a singleton... so that subsequent visits are faster. I do this caching sometimes, but I do exactly as you outline above for the retrieve attribute functionality.
Related
Here is my situation:
I have a 3rd party Component Control which I successfully inherited,
and now I am doing some custumization to it.
Part of that customization, is to change the DefaultValues of some properties it has.
So far it all went OK,
but this control has some "Sub" Classes in it, that I want to change their propeties' DefaultValues too.
By "Sub" Classes I mean:
Let's say my control is called SomeControl,
so it has properties in it, but it also has a property that is expandable,
like: SomeControl.Rows,
The .Rows property returns a RowCollection which has its own properties.
So this is what I mean by "Sub" Class (please correct me if there's a better term for this)
In any case, If I want to change some DefaultValues in the RowCollection class,
I need to inherit it too.
The propblem is that RowCollection's Ctor is internal, so I cannot inherit that class.
So is there any other way for me to change the DefaultValue attribute for a property in a class that I cannot inherit?
Maybe via reflection?
I nee to change it for an instance(object) that I have existing - one instance,
and not for the class in general.. (since after 1 object is created from it, no more are created..)
Thank you
Summary: I don't think it is possible to do this via reflection, but here is how I would do it:
First get the property you want:
var defValAttr = typeof (SomeControl.RowCollection)
.GetProperty("yourProperty")
.GetCustomAttributes(typeof(DefaultValueAttribute), false)
.First()
as DefaultValueAttribute;
DefaultValueAttribute has a .Value property, which is readonly. To modify it you need reflection again to change the private .value field:
var valueField= typeof (DefaultValueAttribute)
.GetField("value", BindingFlags.NonPublic
| BindingFlags.GetField
| BindingFlags.Instance);
valueField.SetValue(defValAttr, yourNewDefaultValue);
I have not tested this myself, but as far as I know this will not work. The objects returned by GetCustomAttributes are not the actual attributes; you can get the values of the real attributes this way, but you cannot change them. (see Can attributes be added dynamically in C#?)
However, even if this would work, it would change the DefaultValue for all instances of SomeControl.Rows, whether they are within your custom derived control or in the base control. There is no way to change only the DefaultValue of a single instance, since the this value is stored only once per class, not once per instance. It would be very wasteful if there was a copy of each attribute for each instance of an object.
So in conclusion, I don't think there is a way to do this.
As an alternative, you could decompile the third-party assembly and add your own assembly with InternalsVisibleTo, that way you can access the internal constructor.
Addendum: There may still be a way to do this, depending on what sort of attribute you want to change. The attributes accessible via reflection are as I said probably unchangeable. However The visual studio editor and the whole WPF component model actually uses a TypeDescriptor to manage attributes on top of the basic attribute system built into the language. You may be able to change the attributes used by the TypeProvider, and if code later accesses the attributes via TypeDescriptor, it may see the changed values.
The following is again untested:
var instanceOfRow = instanceOfYourControl.Rows;
var defValAttr = TypeDescriptor
.GetProperties(instanceOfRow)["yourProperty"]
.Attributes[typeof (DefaultValueAttribute)]
as DefaultValueAttribute;
var valueField= typeof (DefaultValueAttribute)
.GetField("value", BindingFlags.NonPublic
| BindingFlags.GetField
| BindingFlags.Instance);
valueField.SetValue(defValAttr, yourNewDefaultValue);
Greetings all,
I am calling Type.GetProperties(), but after running Dotfuscator, it is returning zero items, when it returned more than zero before.
public class Test
{
public int Number { get; set; }
public void ShowInfo()
{
Type type = this.GetType();
PropertyInfo[] props = type.GetProperties();
Console.WriteLine("type [" + type.Name + "] props count: " + props.Length);
}
}
If I exclude the "Number" property from renaming within Dotfuscator, then it works, but otherwise it doesn't. However, it is not possible for me to do this for all properties in my project, as it would lead to possible bugs.
Are there any workarounds for this method? Or even other "free" obfuscation applications I could use?
I have already tried looking on their website to submit a bug, but I am only using the community edition so there doesn't seem to be as much support for it.
Dotfuscator automatically strips properties (which are just metadata anyway - the real work is done by the get/set pair of methods that are automatically created) during renaming. It also renames the underlying get/set methods as well. Depending on what you are trying to do, you'll need to exclude either the property metadata itself, or the get/set methods (or possibly both) from renaming.
If you need to keep the property metadata intact (for example, to simply list the properties in a Type), you can instruct Dotfuscator to exclude properties from renaming by checking them in the tree view on the Renaming Exclusions tab or using a custom regex property rule. This will only exclude the property metadata - the get/set methods will still be renamed.
If you need to keep the get/set methods (because, for example, you are trying to get or set a property's value by reflection), you can instruct Dotfuscator to exclude those methods from renaming by expanding the property in the tree view and checking the get/set methods underneath, or by using a custom regex method rule.
As the process of obfuscation is not limited to renaming your class members, you can't be sure of that. That's the problem with obfuscation: You basically can't make any assumptions about your class anymore regarding the result of reflection. The only way I can think of is to not use reflection but expressions.
Have a look at this question and its answer to know, what I mean with "expressions": How to raise PropertyChanged event without using string name
I believe there is no human way to change any attribute or field inside an Attribute apart from doing it in the constructor. That is, short of redesigning and recompiling Visual Studio yourself. There is already a similar question posted here:
Change Attribute's parameter at runtime
but I believe the peculiarities of my problem are different enough to require a new post.
I use an enumeration to keep track of the different columns of a DataTable. I use attributes in each enumeration element to indicate the underlying type and the description -in case the .ToString() would give an "ugly" result due to the rigid set of characters that are allowed to name an enumeration element, such as "Tomato_Field" when you want "Tomato Field", and the like. This allows me to place all the related information in the same object, which is, I believe, what it should be. This way I can later create all the columns with a simple and clean foreach that cycles through the elements of the enumeration and extracts the metedata (description and type) to create each column.
Now, some of the columns are autocalculated, which means that during their creation -via DataTable Identifier.Columns.Add.(NameOfColumn,underlyingType,optional: autocalculatedString)- I need to specify a string that determines how it should be calculated. That string must use the names of other columns, which might be in the Description Attribute. The approach that looks logical is to use another attribute that holds the string, which should be built using the names of the other columns, requiring access to the metadata. Now that seems impossible in the constructor: you are forced to provide a constant string. You can't use a method or anything.
This problem could be solved if there were a way to change a property inside the attribute (lets call it AutocalculatedStringAttribute) at runtime. If you access the metadata you can retrieve the string you used at the constructor of the Attribute, and you can of course change that string. However, if you later access the metadata again that change is ignored, I believe the constructor is called every time the metadata is accessed at runtime, thus ignoring any changes.
There are, of course, dirty ways to achive what I am trying to do, but my question is specifically if there is a way to properly use attributes for this. Short of resorting to CodeDOM to recompile the whole assembly with the constructor of the AutocalculatedStringAttribute changed, a certain overkill.
Right, the metadata that's used to initialize the attribute is immutable. But you can add properties and methods to an attribute class that can run code and return relevant info after the attribute object is constructed. The data they rely on doesn't have to be stored in metadata, it can be persisted anywhere.
Of course, such code wouldn't have to be part of the attribute class implementation, it could just as well be part of the code that instantiates the attribute. Which is where it belongs.
It isn't entirely clear to me what code is consuming this attribute, and it matters...
You cannot change an attribute that is burned into the code - you can query it with reflection, but that is about it. However, in many cases you can still do interesting things - I don't know if they apply to your scenario, though:
you can subclass many attributes like [Description], [DisplayName], etc - and while you pass in a constant string (typically a key) to the .ctor, it can return (through regular C#) more flexible values - perhaps looking up the description from a resx to implement i18n
if the caller respects System.ComponentModel, you can attach attributes at runtime to types etc very easily - but much harder on individual properties, especially in the case of DataTable etc (since that has a custom descriptor model via DataView)
you can wrap things and provide your own model via ICustomTypeDescriptor / TypeDescriptionProvider / PropertyDescriptor - lots of work, but provides access to set your own attributes, or return a description (etc) outside of attributes
I don't know how much of this is suitable for your environment (perhaps show some code of what you have and what you want), but it highlights that (re the question title) yes: there are things you can do to tweak how attributes are perceived at runtime.
I wanted to post this as a comment but since I wanted to include some code I couldn't, given the 600 characters limit. This is the cleanest solution I have managed to find, although it does not include all the info to create the columns on the enum, which is my goal. I have translated every field to make it easier to follow. I am not showing some code which has an obvious use (in particular the implementations of the other custom attributes and their static methods to retrieve the metadata, assume that it works).
This gets the job done, but I would ideally like to include the information stored in the strings "instancesXExpString " and "totalInstancesString" in the Autocalculated attribute, which currently only marks the columns that have such a string. This is what I have been unable to do and what, I believe, cannot be easily accomplished via subclassing -although it is an ingenious approach, I must say.
Thanks for the two prompt replies, btw.
And without any further ado, lets get to the code:
// Form in which the DataGridView, its underlying DataTable and hence the enumeration are:
public partial class MainMenu : Form {
(...)
DataTable dt_expTable;
//Enum that should have all the info on its own... but does not:
public enum e_columns {
[TypeAttribute(typeof(int))]
Experiments = 0,
[TypeAttribute(typeof(decimal))]
Probability,
[DescriptionAttribute("Samples / Exp.")]
[TypeAttribute(typeof(int))]
SamplesXExperiment,
[DescriptionAttribute("Instances / Sample")]
[TypeAttribute(typeof(int))]
InstancesXSample,
[DescriptionAttribute("Instances / Exp.")]
[TypeAttribute(typeof(int))]
[Autocalculated()]
InstancesXExp,
[DescriptionAttribute("Total Instances")]
[TypeAttribute(typeof(long))]
[Autocalculated()]
Total_Instances
};
//These are the two strings
string instancesXExpString = "[" + DescriptionAttribute.obtain(e_columns.SamplesXExperiment) + "] * [" + DescriptionAttribute.obtain(e_columns.InstancesXMuestra) + "]";
string totalInstancesString = "[" + DescriptionAttribute.obtain(e_columns.InstancesXExp) + "] * [" + DescriptionAttribute.obtain(e_columns.Experiments) + "]";
public MainMenu() {
InitializeComponent();
(...)
}
private void MainMenu_Load(object sender, EventArgs e) {
(...)
// This is the neat foreach I refered to:
foreach (e_columns en in Enum.GetValues(typeof(e_columnas))) {
addColumnDT(en);
}
}
private void addColumnDT(Enum en) {
//*This is a custom static method for a custom attrib. that simply retrieves the description string or
//the standard .ToString() if there is no such attribute.*/
string s_columnName = DescriptionAttribute.obtain(en);
bool b_typeExists;
string s_calculusString;
Type TypeAttribute = TypeAttribute.obtain(en, out b_typeExists);
if (!b_typeExists) throw (new ArgumentNullException("Type has not been defined for one of the columns."));
if (isCalculatedColumn(DescriptionAttribute.obtain(en))) {
s_calculusString = calcString(en);
dt_expTable.Columns.Add(s_columnName, TypeAttribute, s_calculusString);
} else {
dt_expTable.Columns.Add(s_columnName, TypeAttribute);
}
}
private string calcString(Enum en) {
if (en.ToString() == e_columns.InstancessXExp.ToString()) {
return instancesXExpString;
} else if (en.ToString() == e_columns.Total_Samples.ToString()) {
return totalInstancesString;
} else throw (new ArgumentException("There is a column with the autocalculated attribute whose calculus string has not been considered."));
}
(...)
}
I hope this piece of code clarifies the situation and what I am trying to do.
Currently, I've created a class with ~30 properties to be set. This is done to build up a URL request later on(ie, "http://www.domain.com/test.htm?var1=a&var2=b...&var30=dd").
The issue I'm facing is the property names don't necessarily match the query variable names(this is intended to be different). For example, I may have a variable titled "BillAddress", whereas the query variable will need to be "as_billaddress".
I have no control over the query variable naming scheme as these are set at an external source.
One possible solution I've used is creating a custom attribute and decorating the properties with their respective query counterparts:
[CustomQueryAttribute("as_billaddress")]
string BillAddress{get;set;}
To retrieve the attribute though, requires a little reflection and due to the larger number of properties, I was curious if there is a neater way to accomplish this functionality. Not so much as setting/retrieving custom attributes without reflection, but being able to tie an alternate string variable to any property.
I've also pondered about setting each variable up as a sort of KeyValuePair, with each key representing the query counterpart, but I didn't get too far in that thought.
To summarize/clarify my above backstory, what would you do to associate a string with a property(not the value of the property)?
As always, any comments are greatly appreciated.
I would probably stick with a custom attribute, but the other potential option would be to do something like hold a static Dictionary that had string and property info (or property name), so you could get/set the property directly via this.
Something like:
static Dictionary<string, PropertyInfo> propertyMap = new Dictionary<string, PropertyInfo>();
static MyClass()
{
Type myClass = typeof(MyClass);
// For each property you want to support:
propertyMap.Add("as_billaddress", MyClass.GetProperty("BillAddress"));
// ...
}
You could then just do a dictionary lookup instead of using reflection in each call... This could also be setup fairly easy using configuration, so you could reconfigure the mappings at runtime.
A custom attribute seems like the best option to me - the framework seems to do this a lot as well (specifically with serialization).
If you look at popular ORM mappers then nearly all either use custom attributes or some kind of XML mapping file. The advantage of the latter is that you can modify the mapping without recompiling your application - the downside is that it hurts performance. However, I'd say your choice seems perfectly reasonable.
Is it possible to add attributes at runtime or to change the value of an attribute at runtime?
This really depends on what exactly you're trying to accomplish.
The System.ComponentModel.TypeDescriptor stuff can be used to add attributes to types, properties and object instances, and it has the limitation that you have to use it to retrieve those properties as well. If you're writing the code that consumes those attributes, and you can live within those limitations, then I'd definitely suggest it.
As far as I know, the PropertyGrid control and the visual studio design surface are the only things in the BCL that consume the TypeDescriptor stuff. In fact, that's how they do about half the things they really need to do.
Attributes are static metadata. Assemblies, modules, types, members, parameters, and return values aren't first-class objects in C# (e.g., the System.Type class is merely a reflected representation of a type). You can get an instance of an attribute for a type and change the properties if they're writable but that won't affect the attribute as it is applied to the type.
You can't. One workaround might be to generate a derived class at runtime and adding the attribute, although this is probably bit of an overkill.
Well, just to be different, I found an article that references using Reflection.Emit to do so.
Here's the link: http://www.codeproject.com/KB/cs/dotnetattributes.aspx , you will also want to look into some of the comments at the bottom of the article, because possible approaches are discussed.
No, it's not.
Attributes are meta-data and stored in binary-form in the compiled assembly (that's also why you can only use simple types in them).
I don't believe so. Even if I'm wrong, the best you can hope for is adding them to an entire Type, never an instance of a Type.
If you need something to be able to added dynamically, c# attributes aren't the way. Look into storing the data in xml. I recently did a project that i started w/ attributes, but eventually moved to serialization w/ xml.
Why do you need to? Attributes give extra information for reflection, but if you externally know which properties you want you don't need them.
You could store meta data externally relatively easily in a database or resource file.
Like mentionned in a comment below by Deczaloth, I think that metadata is fixed at compile time. I achieve it by creating a dynamic object where I override GetType() or use GetCustomType() and writing my own type. Using this then you could...
I tried very hard with System.ComponentModel.TypeDescriptor without success. That does not means it can't work but I would like to see code for that.
In counter part, I wanted to change some Attribute values.
I did 2 functions which work fine for that purpose.
// ************************************************************************
public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName, string description)
{
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
if (att != null)
{
var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldDescription != null)
{
fieldDescription.SetValue(att, description);
}
}
}
// ************************************************************************
public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
{
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
if (att != null)
{
var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldDescription != null)
{
fieldDescription.SetValue(att, isReadOnly);
}
}
}
When faced with this situation, yet another solution might be questioning you code design and search for a more object-oriented way. For me, struggling with unpleasant reflection work arounds is the last resort. And my first reaction to this situation would be re-designing the code. Think of the following code, which tries to solve the problem that you have to add an attribute to a third-party class you are using.
class Employee {} // This one is third-party.
And you have code like
var specialEmployee = new Employee();
// Here you need an employee with a special behaviour and want to add an attribute to the employee but you cannot.
The solution might be extracting a class inheriting from the Employee class and decorating it with your attribute:
[SpecialAttribute]
class SpecialEmployee : Employee
{
}
When you create an instance of this new class
var specialEmployee = new SpecialEmployee();
you can distinguish this specialEmployee object from other employee objects. If appropriate, you may want to make this SpecialEmployee a private nested class.