I've encourted a problem recently about cycling between constants of an enum class in .net (that is created from my OWL class, by Rowlex OwlGrinder). Problem was solved by means of using .net reflection (thanks to great help from dear Mr. Jon Skeet):
stackoverflow:problem-cycling-enum-class-values
By solving this, I started using it. After matching a dropDownList selected value to one of the enum class instances, I had to declare the selected object(=Language) to my RDF subject(=learningResource), via a predicate (=hasLanguage).
//learningResource is a new RDF subject, hasLanguage is predicate, and there
//is a new value for it - Language.
System.Reflection.FieldInfo[] resLanFields =
typeof(Language).GetFields();
for (int i = 0; i < resLangFields.Length; i++)
{
if (resLanFields[i].Name.Equals(dropDownList_lang.SelectedValue))
learningResource.hasLanguage = ??? //i-th constant of Language
}
Now the problem appears; I can not use Language[i] (or something like this to select i-th constant of Language class) to assign to hasLanguage. Is there a way to select i-th constant of an enum class (like refelections)?
Would any one please help me in this situation?
The Language class is not an enum in C# terminology. It is an ordinary class with public const string fields. ROWLEX intentionally generates enum-imitating-classes instead of native enums for 2 reasons:
The value of an native C# enum is an integer, while a public const string field can take the URI of the OWL class instance.
The class can have one additional public static string that is "URI" which represents the class URI consistently for every single ROWLEX generated class.
That was the background. If I understood your question right, you had an issue binding the selected name displayed in the dropdown back to the URI, and you wanted to use the position of the element inside the array you created. I would not do it that way. DropDownLists typically have both ID and Value fields for every list item (can be named differently component to component). The ID is expected to be a unique object while the Value is expected to contain something human readable. Set the ID with URI of the "enum" field, and the Value as you have done. So this is how you populate your dropdown:
System.Reflection.FieldInfo[] resLanFields = typeof(Language).GetFields();
foreach(FieldInfo field in resLanFields)
{
ListItem item = new ListItem();
item.ID = field.GetValue(null); // takes the URI value of the const field
item.Value = field.Name; // takes the name of the const field
dropDownList_lang.AddItem(item);
}
And when the user made his/her choice, this is how you read the result out:
learningResource.hasLanguage = (string) dropDownList_lang.SelectedItem.ID;
Since there is implicit casting operator implemented on the ROWLEX enum-imitating-class (string=>Language) you can safely set your triple subject as a string. Should compile without issue. Simple, isn't it?
;)
I'd say
resLanFields[i].GetValue(null)
but if this works, don't vote me up, this was in Jon's original answer.
Related
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.
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.
This is a bit of a strange one with Sitecore... Basically I'm accessing an item from the Content API but it's not populating the Item.Fields hashtable with keys based on the text for the field (I guess I'd call this a field name) but rather with a GUID.
For example, here is some code I'm using to get an item:
var database = global::Sitecore.Configuration.Factory.GetDatabase("master");
var item = database.GetItem("/sitecore/content/Home");
item.Fields.ReadAll(); // edit, per recommendation... does not work
Sitecore.Data.Fields.Field f = item.Fields["SomeText"];
Assert.IsNotNull(f): // This fails
If I set a breakpoint and debug, I can see that there are values (indeed, the correct values) inside the Item.Fields hashtable, but the keys are all based on GUIDs rather than "field names" as most code samples regarding usage of this API suggest.
EDIT: Upon closer inspection, the DisplayName and Name fields are coming back as empty strings from the API (note these are clearly defined in Sitecore so still not sure what the issue is). It appears these might be used in conjunction with GUID as some sort of key for the hashtable.
Question: Is there something I'm doing wrong here? I've published the data template and the content item. Clearly the connection is being made because I'm getting results back from the API and even the correct values, just not the keys I'm expecting to use to reference the data values.
References:
http://sdn.sitecore.net/upload/sitecore6/content_api_cookbook-a4.pdf - checkout the example right at the top of page 28 where they access the "title" field. Also, check out the example directly below in 4.1.1 "How to Access System Fields" where they use static helpers with the GUIDs instantiated in a private static constructor. Is this the preferred method for accessing "user defined" fields?
Screenshot of sample data from Sitecore (notices the GUIDs as keys):
Code Samples from above linked document:
Accessing the "title" field:
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Items.Item home = master.GetItem("/sitecore/content/home");
Sitecore.Data.Fields.Field titleField = home.Fields["title"];
if(titleField!=null)
{
home.Editing.BeginEdit();
titleField.Value = "//TODO: replace with appropriate value";
home.Editing.EndEdit();
}
Accessing the system field "ArchiveDate":
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Items.Item sample = master.GetItem("/sitecore/content/home/sample");
Sitecore.Data.Fields.DateField archiveField =
sample.Fields[Sitecore.FieldIDs.ArchiveDate];
Decompiling the Sitecore.Kernel.dll we can see that:
public static class FieldIDs
{
// stripped down version
/// <summary>The ID of the 'Archive date' field.</summary>
public static ID ArchiveDate;
static FieldIDs()
{
FieldIDs.ArchiveDate = new ID("{56C15C6D-FD5A-40CA-BB37-64CEEC6A9BD5}");
}
}
If I understand correctly, you want the Fields collection to return all the fields available for that item, even if they do not have a value. By default, Sitecore will only return those fields that have a value.
You can solve this by calling the ReadAll() method before accessing the fields collection.
So in your example:
item.Fields.ReadAll();
Sitecore.Data.Fields.Field f = item.Fields["SomeText"];
Assert.IsNotNull(f): // This succeeds
I had a problem with identical symptoms. The root cause for me was a publishing issue. The folder containing my template was not published, though the template itself was. So I could see the fields in the debugger with the correct values and ids, but not the names. The solution was to ensure that all the parents of my template were also published.
So, I ended up going the route I mentioned in the question (which is what Sitecore uses internally and, #technophoria414 mentioned, a Sitecore developer best practice).
Basically:
namespace MyProject.Core.Data.Sitecore.Fields
{
public static class ContentItem
{
// stripped down version
public static ID DESCRIPTION_TEXT;
static ContentItem()
{
DESCRIPTION_TEXT= new ID("{56C15C6D-FD5A-40CA-BB37-64CEEC6A9BD5}"); // this will be some GUID out of Sitecore
}
}
}
Usage would be something like this:
var query = string.Format("fast:/sitecore/content/HomePageItems//*[#ContentSlug='{0}']", input);
var item = Database.SelectSingleItem(query);
var descriptionText = item.Fields[ContentItem.DESCRIPTION_TEXT].Value;
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.
I have a list of strings which are candidates for Enumerations values. They are
Don't send diffs
500 lines
1000 lines
5000 lines
Send entire diff
The problem is that spaces, special characters are not a part of identifiers and even cannot start with a number, so I would be sanitizing these values to only chars, numbers and _
To keep the original values I thought of putting these strings in the DescriptionAttribute, such that the final Enum should look like
public enum DiffBehvaiour
{
[Description("Don't send diffs")]
Dont_send_diffs,
[Description("500 lines")]
Diff_500_lines,
[Description("1000 lines")]
Diff_1000_lines,
[Description("5000 lines")]
Diff_5000_lines,
[Description("Send entire diff")]
Send_entire_diff
}
Then later using code I will retrieve the real string associated with the enumeration value, so that the correct string can be sent back the web service to get the correct resource.
I want to know how to create the DescriptionAttribute using System.Reflection.Emit
Basically the question is where and how to store the original string so that when the Enumeration value is chosen, the corresponding value can be retrieved.
I am also interested in knowing how to access DescriptionAttribute when needed.
Ok, if you really want to use reflection:
DiffBehvaiour value = DiffBehvaiour.Dont_send_diffs;
FieldInfo enumField = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = (DescriptionAttribute)enumField.
GetCustomAttributes(typeof(DescriptionAttribute), true)[0];
Console.WriteLine(attribute.Description);
$> Don't send diffs
Obviously there is no error handling, etc, but the basic idea is there.
Update
I now think I see the point of your question, which myself and the other people that answered actually missed.
You want to decorate an enum with attributes at runtime i.e. add attributes to a type at runtime. Adding attributes to a type at runtime is not possible.
However these is support in the .Net for a type metadata engine via : TypeDescritor:
MSDN http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.aspx
Example http://geekswithblogs.net/abhijeetp/archive/2009/01/10/dynamic-attributes-in-c.aspx
The TypeDescritor framework allows you to dynamically provide type information rather than actually dynamically decorating types directly - it is a layer of indirection.
You may be able to bend this mechanism to support what you want to do, but at the end of the day you will need to maintain a lookup for your enum members to provide the description strings. Using a lookup structure to maintain a mapping between your enum members and description string was my first answer and the first answer to this question...
You could write a generic method like this:
class EnumExtensions
{
public static string GetDescription<TEnum>(TEnum value)
// inexpressible generic constraint TEnum : System.Enum
{
// reflection lookup of this value per #chibacity answer
}
public static IDictionary<TEnum,string> GetDescriptions<TEnum>()
// inexpressible generic constraint TEnum : System.Enum
{
// do the reflection lookups once and build a dictionary
var result = new Dictionary<TEnum, string>();
foreach(string name in Enum.GetNames(typeof(TEnum))
{
var value = (TEnum)Enum.Parse(typeof(TEnum), name);
var description = GetDescription(value);
result.Add(value, description);
}
return result;
}
}