Get property private member name - c#

So I have this.
private int _SomeDataBaseField_;
public int ID
{
get { return _SomeDataBaseField_; }
set { _SomeDataBaseField_ = value; }
}
What I am trying to do is map the property name and the private field name in a way that I can pull the private field name using the property name only and without using any attributes or tags.
So my question is:
Is there any way to deduce the private field name using only the property name? Something like
string PrivateFieldName = typeof(T).GetProperty("ID").GetPrivateFieldName();
Where PrivateFieldName would be SomeDataBaseField.
I tried to use reflection but no luck.. This is as far as I got and it only shows the private field type (Int32) which is not very helpful.
foreach (PropertyInfo item in typeof(T).GetProperties())
{
LocalVariableInfo lv = item.GetAccessors()[0].GetMethodBody().LocalVariables[0];
}
Edit:
I feel I need to explain why I need this.
So I have a class that contains 1200+ properties and they all have private fields (backing fields). now I already spent countless hours creating the mysql database table for that class and now that I am using it I realized that I am going to have to manually type the field name every time I need to update one of the fields in the database. So I thought I would use the private field name as a database column and then supply the update function with the property name which would then look up some collection of <'PropertName, PrivateName'> for the corresponding private field name and use that as the database field name. This would not only save time but it would also limit the need for typing the field names over and over again whenever they need to be updated or parsed.
Thanks in advance.

Use typeof(T).GetFields instead.
A Property in C# is a logical grouping of two CLR Methods (a getter and a setter). A property does not necessarily have a single backing field - it doesn't have to have any, or it could have multiple. You shouldn't make that assumption.

Not every property is backed by a single field - all variants 0-infinity are possible, so you need to review what your goals are.
Proper way would be to parse IL of each property get/set pair and find what (if any) packing field their are using. Such approach would let you detect non-trivial properties that use more than one backing field (or none at all). GetMethodBody is starting point for such code - some info can be found in Can I use reflection to inspect the code in a method?
More practical way would be to rely on some sort of convention to find matches.
I.e. for auto-properties compiler generates predictable names (implementation-dependent) and you can find matching field as shown in Is it possible to access backing fields behind auto-implemented properties?.
For other cases there is usually some naming convention - i.e. field with same name but different case/prefix/suffix. Basic string matching would help for such cases.

Related

Sitecore Field Id's vs Field Name's

I read it in "Professional Sitecore Development" book by - John West saying that it's best practice to use Field ID's instead of Field names while getting the Item Field value.
But sitecore Controls like sc:text, sc:link, sc:image etc have an attribute called field which uses field name. So, i am confused now whether to change the whole project to Field ID's or leave it with field names to be consistent with sitecore usage.
Any suggestions will be appreciated.
Yes, Sitecore allows you to use Names and IDs. Also Sitecore allows you to have identical fields names in a same template, what may cause some confusion. IDs, of course, can not be duplicated.
I believe it is more reliable to use IDs instead of names. Names can easily be changed on Sitecore, and it is hard to find the error when that happens. You won't get compilation error or anything like that until someone notice the field value is not there.
A good approach is to use a code generator (like T4 or TDS) to create strongly typed classes to be used in your code. Something like:
public static struct MyTemplate
{
public static struct MyGroup1
{
public static readonly ID Foo = new ID("{1111111-1111-1231-1231-12312323132}");
}
public static struct MyGroup2
{
public static readonly ID Foo = new ID("{9999999-9999-xxxx-1231-12312323132}");
}
}
Then you go that way on your controls:
#Html.Sitecore().Field(MyTemplate.MyGroup.Foo); //where foo returns the id.
Hope that helps..
As an FYI adding to #RobertoBr's excellent answer, Sitecore uses GUIDs internally to access well known fields. If you decompile Sitecore.Kernel.dll and look in the static class Sitecore.FieldIDs you will see a list of fields you would be very familiar with using, e.g.
public static ID Created = new ID("{25BED78C-4957-4165-998A-CA1B52F67497}");
public static ID CreatedBy = new ID("{5DD74568-4D4B-44C1-B513-0AF5F4CDA34F}");
public static ID DisplayName = new ID("{B5E02AD9-D56F-4C41-A065-A133DB87BDEB}");
Very similar to what RobertoBr has suggested.
I would recommend you to use field IDs instead of field names in all cases.
Field IDs usage prevents a lot potential mistakes, misspell, etc..
You don't need to worry about correct behavior if you will decide to rename some fields (or other developer will decide to rename his fields).
If you use template's inheritance, you may have potential bugs with duplicates of field names.
Field IDs usage prevents unnecessary processing. Because when you are using field name, Sitecore resolves field ID by field name and after that retrieves field by ID.

How can I get a variable/field name through reflection on properties?

Lets say you have:
PropertyInfo propInfo; // Assume it was already initialized with property of a private field
(private int m_Number)
If I'll do propInfo.PropertyType.Name I guess I will get something like int32 or int.
Two questions:
1. How can I extract the variable name "m_Number" through propInfo.
Note: Once I was able to do so by iterating a FieldInfo instead of propInfo.
2. If I want to use reflection to know all kind of fields of a given class, what should be the right way:
A. Iterating over all properties(in assumption every field has a property)
B. Iterating over all the fields directely.
Thanks
A property is not necessarily related to a field - in fact, a property is a little more than a syntactic sugar on top of a pair of functions.
If your code uses some sort of a convention for naming variables that back properties (such as prepending them with m_, as in your example) you could rely upon that convention to retrieve the variable name. In all other cases, there is no direct connection, and no way to retrieve that relationship through the reflection API.

What fields and properties should I serialize?

I do not think this is a duplicate. I have done some reading but did not find anything the same as this. It seems that fields can be serialized in binary formatters and in protobuf but not in XML. I don't know about JSON.
I am looking at replacing the standard .NET binary serializer with protobuf-net. The reason is to improve speed and get a smaller persisted file size.
In NET Binary I just marked the classes as serializable and left it at that. Not good I suspect.
With protobuf-net I need to specify what gets serialized with the [ProtoMember()] attribute. My newbie testing shows that private fields get serialized if so marked as do auto properties.
I do not want to change the class code definitions at all since I still need to be able to deserialize the old persisted data created by the NET serializer. I have a mixture of:
Private fields that get used inside the class
Private fields whose value gets set in constructors
Private fields that are backing fields for non automatic properties
Properties with the backing fields above
Auto properties
Properties with no setters that return some calculation or value determined internally
and probably some others. In other words pretty much every type of field and property.
I guess I need to persist any value that represents the state of the object that cannot be constructed after deserialization from the file.
I suppose there would be no harm in persisting every field and property but that would just make the job slower and the file bigger than it needs to be.
I think I can ignore private fields that are used only inside the class and are not set from outside.
I think I should persist those fields that are set in constructors.
I am not sure about backing fields - is it better to persist them or their public property?
I must persist auto properties
I can't persist properties with no setters so I need to persist whatever fields/properties get used in their calculations.
Am I on the right track or missing the point.
Thanks in advance.
We can't say what needs to be serialized. BinaryFormatter works on an "all fields" basis (unless they are explicitly marked not for serialization). You could use the same approach, but if you're using automatically implemented properties (which is fine) then note that you cannot add attributes to the backing field - unlike field-like events, the following is not valid c#:
[field:ProtoMember(1)] // not valid
public int X { get; set; }
This means that your only sensible choice is to decorate the property:
[ProtoMember(1)]
public int X { get; set; }
Because, if you change the automatically implemented property to a regular property, you will have broken BinaryFormatter's deserialization, since the field-name will have changed. That's fine, though - there's nothing wrong with marking either the fields or the properties (or both in the same type) for serialization. Another consideration on some platforms is accessibility: a private field may be inaccessible, where-as a public field works fine. And obviously public fields are pretty uncommon.
So:
decide what needs to be serialized (I can't tell you this)
mark it for serialization
do not change anything from automatically-implemented property to a regular property if you need BinaryFormatter to keep working (protobuf-net doesn't care if you change this)

C# - Get property in member class using Reflection

SHORT VERSION
What's the best way to use reflection to turn something like string prop = "part1.first_name"; into a System.Reflection.PropertyInfo, so that I can use the GetValue and SetValue functions?
LONG VERSION
I'm using ASP .NET MVC to build a questionnaire for my organization. It's very long, so it's divided into several different pages. Since it's not uncommon for us to get requests like, "Can you move this question to that page, and this other question to another page," I need to build this to be pretty flexible for a junior programmer to change.
My model is a complex class (it's got five member classes that have mostly primitive-typed properties on them).
So, I access it by doing things like Model.part1.first_name or Model.part2.birth_date.
Since the same model is used on all of the pages, but not all of the questions are on every page, I have ActionAttributes that essentially clear out all of the properties that were submitted on the form except for the ones that were displayed on that page (so someone can't inject a hidden field into the form and have the value persist to the database).
I want to make sure that I only save valid field values and don't let the user proceed to the next page until the current one is entirely OK, but I also want to save the values that are valid, even if the user isn't allowed to proceed.
To do this, I have a function that takes two instances of my model class, a reference to the ModelStateDictionary, and a string[] of field names like "part1.first_name" and "part2.birth_date". That function needs to copy all of the values listed in the string array that do not have validation errors from the first (ie, form-submitted) object into the second (ie, loaded from the db) object.
As stated above, what's the best way to use reflection to turn something like "part1.first_name" into a System.Reflection.PropertyInfo, OR, is there a better way to accomplish this?
var infoParts = prop.Split('.');
var myType = Type.GetType(infoParts[0]);
var myPropertyInfo = myType.GetProperty(infoParts[1]);
Assuming "part1" is your type. Although this is very limited and very dependent on the string being in the correct format and the type being in the current scope.
I would probably handle this differently, using data. I would keep, in the database, which step each question belongs to. To render that step, I would select the questions that match that step and have a model that contains a list of question id/question pairs. Each input would be identified by the question id when posted back. To validate, simply compare the set of question ids with the expected ids for that step. This way, to change which question goes in which step is to only change the data in the database.
If you do end up going down that road, you'll need to split the string into parts and recursively or iteratively find the property on the object at each step.
PropertyInfo property = null;
Type type = questionModel.GetType();
object value = questionModel;
object previousObj = null;
foreach (var part in questionId.Split('.'))
{
property = type.GetProperty(part);
previousObj = value;
value = property.GetValue(value,null);
type = value.GetType();
}
// here, if all goes well, property should contain the correct PropertyInfo and
// value should contain that property's value...and previousObj should contain
// the object that the property references, without which it won't do you much good.

Set or change Attribute's properties or fields at runtime in C#. Possible?

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.

Categories