This question already has an answer here:
Using PropertyInfo.GetValue()
(1 answer)
Closed 5 years ago.
I have the following class:
public class MagicMetadata
{
public string DataLookupField { get; set; }
public string DataLookupTable { get; set; }
public List<string> Tags { get; set; }
}
And an instance of it, let's say:
MagicMetadata md = new MagicMetadata
{
DataLookupField = "Engine_Displacement",
DataLookupTable = "Vehicle_Options",
Tags = new List<String>{"a","b","c"}
}
Given the MagicMetadata instance, I need to create a new object for each property, e.g.:
public class FormMetadataItem
{
public string FormFieldName { get; set; }
public string MetadataLabel { get; set; }
}
So I am trying something like this as per c# foreach (property in object)... Is there a simple way of doing this?
foreach (PropertyInfo propertyInfo in md.GetType().GetProperties())
{
new FormMetaData
{
FormFieldName = propertyInfo.Name,
MetadataLabel = propertyInfo.GetValue(metadata.Name) //This doesn't work
}
}
What I don't understand is how I get the value for the property that I am looping through. I don't understand the documentation at all. Why do I need to pass it the object? What object?
P.S. I looked through the existing answers here, and I don't see a clear answer.
Update to:
foreach (PropertyInfo propertyInfo in md.GetType().GetProperties())
{
new FormMetaData
{
FormFieldName = propertyInfo.Name,
MetadataLabel = propertyInfo.GetValue(md) // <--
}
}
PropertyInfo.GetValue() expects an instance of the object that
contains the property whose value you're trying to get. In your
foreach loop, that instance seems to be md.
Also note the distinction between property and field in C#. Properties are the members that have get and/or set:
class MyClass {
string MyProperty {get; set;} // This is a property
string MyField; // This is a field
}
And while reflecting, you need to access these members separately via the myObj.GetType().GetProperties() and myObj.GetType().GetFields() methods.
Related
Consider the following class -
public class User
{
[Selected]
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[Selected]
public int Code { get; set; }
public object GetValue()
{
// need to do something here
}
}
[Selected] here is nothing but a marker attribute. I want GetValue method to return an object which will have the [Selected]-marked properties with corresponding values. That is, in the code below -
private static void Execute()
{
User user = new User
{
Name = "alice",
Email = "alice#liddell.com",
Password = "123456",
Code = 1234
};
var value = user.GetValue();
}
value should be an object with two properties Name and Code which should have the values "alice" and 1234 respectively.
After some searching I tried ExpandoObject (which I never used before) -
public object GetValue()
{
var dictionary = this.GetType().GetProperties().Where(p => p.GetCustomAttribute(typeof(Selected), false) != null).ToDictionary(p => p.Name);
dynamic expando = new ExpandoObject();
foreach (var item in dictionary)
{
object value = item.Value.GetValue(this);
((IDictionary<string, object>)expando).Add(item.Key, value);
}
return expando;
}
But it didn't serve my purpose - the client/consumer of value object somehow couldn't read/access the property values.
Any suggestions?
Edit :
There might be a lot of classes like User and the GetValue method will be called from within a generic method. So, at runtime I have no way to know what type the object is and which properties are marked.
To access the fields by name it is easier to cast the returned object to IDictionary:
var value = (IDictionary<string, object>) user.GetValue();
Console.WriteLine(value["Name"]);
Simplify your method to this:
public Dictionary<string, object> GetValue()
{
var dictionary = this.GetType()
.GetProperties()
.Where(p => p.GetCustomAttribute(typeof(Selected), false) != null)
.ToDictionary(p => p.Name, p => p.GetValue(this));
return dictionary;
}
Use:
var value = user.GetValue(); // value is Dictionary
foreach (var kvp in value)
{
Console.WriteLine(kvp);
}
If you wish POCO, then you can do it like follows
public class User
{
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public int Code { get; set; }
public SelectedUserProperties GetValue()
{
return new SelectedUserProperties
{
Name = Name,
Code = Code
};
}
}
public class SelectedUserProperties
{
public string Name { get; set; }
public int Code { get; set; }
}
It is assumed that the selected properties are known in advance, before compilation.
This makes the marker attribute unnecessary and can be completely removed.
What you did works well, you just have to use the keyword dynamic when you call the method GetValue.
dynamic value = user.GetValue();
If you are using var, value will be of the same type as the return type of your function (i.e object) at compile time. Therefore, if you try to do value.Name your compiler won't allow it because the class Object doesn't have any attribute Name.
dynamic tells your program to do the type checking at runtime.
This question already has an answer here:
Using PropertyInfo.GetValue()
(1 answer)
Closed 5 years ago.
I have the following class:
public class MagicMetadata
{
public string DataLookupField { get; set; }
public string DataLookupTable { get; set; }
public List<string> Tags { get; set; }
}
And an instance of it, let's say:
MagicMetadata md = new MagicMetadata
{
DataLookupField = "Engine_Displacement",
DataLookupTable = "Vehicle_Options",
Tags = new List<String>{"a","b","c"}
}
Given the MagicMetadata instance, I need to create a new object for each property, e.g.:
public class FormMetadataItem
{
public string FormFieldName { get; set; }
public string MetadataLabel { get; set; }
}
So I am trying something like this as per c# foreach (property in object)... Is there a simple way of doing this?
foreach (PropertyInfo propertyInfo in md.GetType().GetProperties())
{
new FormMetaData
{
FormFieldName = propertyInfo.Name,
MetadataLabel = propertyInfo.GetValue(metadata.Name) //This doesn't work
}
}
What I don't understand is how I get the value for the property that I am looping through. I don't understand the documentation at all. Why do I need to pass it the object? What object?
P.S. I looked through the existing answers here, and I don't see a clear answer.
Update to:
foreach (PropertyInfo propertyInfo in md.GetType().GetProperties())
{
new FormMetaData
{
FormFieldName = propertyInfo.Name,
MetadataLabel = propertyInfo.GetValue(md) // <--
}
}
PropertyInfo.GetValue() expects an instance of the object that
contains the property whose value you're trying to get. In your
foreach loop, that instance seems to be md.
Also note the distinction between property and field in C#. Properties are the members that have get and/or set:
class MyClass {
string MyProperty {get; set;} // This is a property
string MyField; // This is a field
}
And while reflecting, you need to access these members separately via the myObj.GetType().GetProperties() and myObj.GetType().GetFields() methods.
I had a similar question before, but this one will need a different solution.
I have object on my Model and object on my service.
I need to set value of Model's object property to a value of properties coming from the service's List<TicketReportPropertyEntity> if both objects' properties are the same.
This is a Model:
public class MyModel{
public ObjectAEntity ObjectAData { get; set; }
public ObjectBEntity ObjectBData { get; set; }
}
ObjectAEntity has a property called "SalesAmount"
This is a service:
public class MyScreenClass
{
public List<TicketReportPropertyEntity> TicketReportPropertyEntities { get; set; }
}
public class TicketReportPropertyEntity
{
public decimal Amount{get;set;}
public ReportPropertyEntity ReportProperty {get;set;}
}
public class ReportPropertyEntity
{
public string ReportGroup { get; set; }
public string PropertyName { get; set; }
}
All the properties, their values and which section(ReportGroup) on the screen they belong to (ObjectAData to the LeftSection and ObjectBData to the RightSection) I'm getting using a reflection from List<TicketReportPropertyEntity> in the following method:
private void SetValues(MyModel m, ObjectAEntity bo, object objectType)
{
string leftSection = "LeftSection";
string rightSection = "RightSection";
m.ObjectAData.SaleAmount = bo.ObjectAData.SaleAmount;
foreach (var ticketReportEntity in mol.TicketReportPropertyEntities)
{
var type = ticketReportEntity.GetType();
PropertyInfo reportProperty = type.GetProperty("ReportProperty");
PropertyInfo reportPropertyName = typeof(ReportPropertyEntity).GetProperty("PropertyName");
PropertyInfo reportPropertyReportGroup = typeof(ReportPropertyEntity).GetProperty("ReportGroup");
PropertyInfo amountProperty = type.GetProperty("Amount");
ReportPropertyEntity reportPropertyValue = (ReportPropertyEntity)reportProperty.GetValue(ticketReportEntity, null);
string reportPropertyNameValue = (string)reportPropertyName.GetValue(reportPropertyValue, null);
decimal value = (decimal)amountProperty.GetValue(ticketReportEntity, null);
//here I need to see if Model's object has the same property as in `ReportProperty` class.
//here I need to find out if the ObjectAEntity has the same property as ReportProperty
if (has)
{
//need to set the value of the Model's `ObjectAEntity` property
}
}
How can I do something like that?
To accomplish this, you would attempt to get the property by the string value stored in the current TicketReportPropertyEntity.ReportPropertyEntity.PropertyName. Since you already have a lot of this setup, it only takes a couple more lines of code.
//here I need to find out if the ObjectAEntity has the same property as ReportProperty
//Attempt to grab the PropertyInfo that you want to set
var objectAEntityReportProperty = bo.GetType().GetProperty(reportPropertyNameValue);
//If it is not null, you have found a match
var has = objectAEntityReportProperty != null;
if (has)
{
//need to set the value of the Model's `ObjectAEntity` property
//Then, set the value
objectAEntityReportProperty.SetValue(bo, ticketReportEntity.Amount);
}
I have come upon an issue I can't seem to figure out. I'm sure there's a simple explanation to this, but I don't understand why I get a System.Reflection.TargetException: 'Object does not match target type' when I try to get a property from (in this case) the employee object.
employee.GetType().GetProperty(property.Name)
Searching for the error returns many results describing problems with calling the Set/GetValue methods, but I haven't found a solution to this one.
I've set a breakpoint where the exception is thrown and it shows that property.Name is indeed a value - and a real property of the object. I've also tried manually specifying a property I know exists. Still the same.
Any suggestions?
EDIT: Tried the following instead:
Type type = typeof (Employee); //Throws the TargetException
PropertyInfo theProperty = type.GetProperty(property.Name);
And now the same exception is thrown at the first line above instead.
EDIT: Added code and more details about the application I'm building.
Class definition for Employee (to simplify mapping to the JSON data this class "represents", the class/fields are in Norwegian - which is the format/language the data comes in, sorry :-).)
"Ansatt" = Employee. "Ansattnummer" = EmployeeNo.
[JsonObject]
public class Ansatt
{
public int Ansattnummer { get; set; }
public string Fornavn { get; set; }
public string Etternavn { get; set; }
public int Pin { get; set; }
public string Adresse { get; set; }
public int Postnummer { get; set; }
public string Poststed { get; set; }
public int TlfPrivat { get; set; }
public int MobilTlf { get; set; }
public string EpostAdresse { get; set; }
public DateTime Fodt { get; set; }
}
My application retrieves a given dataset from a web service - it could be employees, projects or a few other possible datasets. What data to fetch is determined at runtime - by the user. The user can also specify via URL-query which portions, e.g. columns, of the dataset he/she wants. The program then creates a csv-file with the selected data.
Here's the code I use for this:
if (records != null && records.Count != 0) //records contains the chosen dataset - in this case Employees (Ansatt).
{
if (records.GetType() == typeof (List<Ansatt>))
{
foreach (var model in records as List<Ansatt>)
{
var temp = new Ansatt();
foreach (var property in model.GetType().GetProperties())
{
var currentProperty = model.GetType().GetProperty(property.Name);
if (currentProperty != null)
{
Type type = typeof (Ansatt); //Throws System.Reflection.TargetException: 'Object does not match target type'
PropertyInfo tempProperty = type.GetProperty(property.Name);
tempProperty.SetValue(temp, currentProperty.GetValue(property.Name));
}
}
csv.WriteRecord(temp);
}
}
}
You need to specify the name of the property
PropertyInfo value = employee.GetType().GetProperty("Name");
As MSDN goes, you should use it this way:
class MyClass {
private int myProperty;
// Declare MyProperty.
public int MyProperty {
get {
return myProperty;
}
set {
myProperty = value;
}
}
}
public class MyTypeClass {
public static void Main(string[] args) {
try {
// Get the Type object corresponding to MyClass.
Type myType = typeof(MyClass);
// Get the PropertyInfo object by passing the property name.
PropertyInfo myPropInfo = myType.GetProperty("MyProperty");
// Display the property name.
Console.WriteLine("The {0} property exists in MyClass.", myPropInfo.Name);
// Instantiate MyClass
var myObject = new MyClass()
{
MyProperty = 5
};
// Get value using reflection
Console.WriteLine("My property value for my object is {0}.", myPropInfo.GetValue(myObject));
} catch (NullReferenceException e) {
Console.WriteLine("The property does not exist in MyClass." + e.Message);
}
}
}
For your code, when you want to get the property value of an object instance, you should pass object as reference to PropertyInfo.GetValue(object) function.
Instead of this:
tempProperty.SetValue(temp, currentProperty.GetValue(property.Name));
Do this:
tempProperty.SetValue(temp, currentProperty.GetValue(model));
For you to get the property of object through reflection, make it sure that the property name is public with getter and setter else it will return null.
Ex.
public class Employee
{
public string YouProperty { get; set; }
}
var employee = new Employee();
var result = employee.GetType().GetProperty("YouProperty");
// The result is property info
Kindly read some information here.
I have an abstract class that looks like so:
public abstract class PageObjectsBase
{
public abstract string FriendlyName { get; }
public abstract string PageObjectKeyPrefix { get; }
public abstract string CollectionProperty { get; }
}
And a class that derives from PageObjectsBase:
public class PageRatingList : PageObjectsBase
{
public IList<PageRating> PageRatings { get; set; }
public PageRatingList()
{
this.PageRatings = new List<PageRating>();
}
public override string CollectionProperty
{
get
{
var collectionProperty = typeof(PageRatingList).GetProperties().FirstOrDefault(p => p.Name == "PageRatings");
return (collectionProperty != null) ? collectionProperty.Name : string.Empty;
}
}
public override string FriendlyName
{
get
{
return "Page feedback/rating";
}
}
public override string PageObjectKeyPrefix
{
get
{
return "pagerating-";
}
}
}
And a PageRating class which PageRatingList.PageRatings is holding a collection of:
public class PageRating : PageObjectBase
{
public int Score { get; set; }
public string Comment { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
The PageRatingList is being stored in a database (EPiServer's Dynamic Data Store, more specifically using the Page Object Manager). I need to create some reporting functionality and am essentially loading all reports that derive from PageObjectBase. When it comes to returning the data, the code will never know at compile time what type of data it is to load, so I am using Reflection. In my reporting class I have:
//this gives me the right type
var type = Type.GetType("MyNameSpace.PageRatingList", true);
var startPageData = this._contentRepository.Get<PageData>(startPage);
PageObjectManager pageObjectManager = new PageObjectManager(startPageData);
//this loads the instances from the DB
var props = pageObjectManager.LoadAllMetaObjects()
.FirstOrDefault(o => o.StoreName == "Sigma.CitizensAdvice.Web.Business.CustomEntity.PageRatingList");
//this gives me 4 PropertyInfo objects (IList: PageRatings, string : CollectionProperty, string :FriendlyName, string : PageObjectKeyPrefix)
var properties = props.Value.GetType().GetProperties();
I can then iterate through the PropertyInfo objects using:
foreach (var property in properties)
{
//extract property value here
}
The issue I am having is that I cannot figure out how to get the value of each of the propertyinfo objects. In addition, one of those properties is type List and again we wont know the type of T until runtime. So I also need some logic that checks if one of the PropertyInfo objects is of type List and then provides access to each of the properties in the List - the List being of type PageRating.
Can anyone help here? I've not really used reflection in the past so I am winging my way through it, rightly or wrongly!
Many thanks
Al
I may be missunderstanding the problem, but i think you may use something like this:
var props = new PageRatingList(); /*actual instanse of the object, in your case, i think "props.Value" */
var properties = typeof(PageRatingList).GetProperties();
foreach (var property in properties)
{
if (property.PropertyType == typeof(IList<PageRating>))
{
IList<PageRating> list = (IList<PageRating>)property.GetValue(props);
/* do */
}
else
{
object val = property.GetValue(props);
}
}
Hope this helps to find your solution.