Obtain members' name and value - c#

I have the following method to return a Dictionary<string, string> with the names of all public members (fields and properties) of an object as the dictionary key. I can get the name of the members, but I can't get their values. Could anyone tell me how to achieve this in the method below:
public Dictionary<String, String> ObjectProperty(object objeto)
{
Dictionary<String, String> dictionary = new Dictionary<String, String>();
Type type = objeto.GetType();
FieldInfo[] field = type.GetFields();
PropertyInfo[] myPropertyInfo = type.GetProperties();
String value = null;
foreach (var propertyInfo in myPropertyInfo)
{
value = (string)propertyInfo.GetValue(this, null); //Here is the error
dictionary.Add(propertyInfo.Name.ToString(), value);
}
return dictionary;
}
Error:
Object does not match target type.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Reflection.TargetException: Object does not match target type.

Two things here:
You're passing in this, instead of objeto, which means you're trying to read the properties off of the wrong object.
You're not ensuring that you're only trying to read properties that aren't indexers.
Try changing the foreach to this:
foreach (var propertyInfo in myPropertyInfo)
{
if (propertyInfo.GetIndexParameters().Length == 0)
{
value = (string) propertyInfo.GetValue(objeto, null);
dictionary.Add(propertyInfo.Name.ToString(), value);
}
}

A note, here:
foreach (var propertyInfo in myPropertyInfo)
{
value = (string) propertyInfo.GetValue(this, null); //Here is the error
dictionary.Add(propertyInfo.Name.ToString(), value);
}
You are assuming that ALL your properties are strings. Are they?
If they aren't, but you want strings anyway, you can use this code:
object objValue = propertyInfo.GetValue(objeto, null);
value = (objValue == null) ? null : objValue.ToString();
The above code also takes into consideration that property values may be null. I didn't take into consideration the possibility of indexed properties, but if you have any, you'll need to accommodate them.
Also, as Lasse V. Karlsen has pointed out, by passing this instead of objeto, you are trying to pull property values from the parent class of the method, not objeto. If they aren't the same object, you won't get the results you want; if they aren't even the same type of object, then you'll get an error.
Finally, you've used the term "attributes", which refers to something other than properties in .NET, and also you've referred to class variables, which are also not properties. Are the properties actually what you want, as opposed to "fields" or attributes applied to the definition of the class?

Related

Serialise object - GetProperties() causes stack overflow?

I'm trying to serialise all the properties of an object that by default cannot be serialised (the object is of type SPGroup which is sealed and has no empty constructor) so I'm copying all of the properties from the object which I will then serialise.
I get the data from the properties with the code below:
private dynamic GetSerializableProperties<T>(T objToCopy, dynamic dataContainer = null)
{
// Copy the properties into dataContainer, if it's not set
if (Object.ReferenceEquals(null, dataContainer))
{
dataContainer = new ExpandoObject() as IDictionary<string, object>;
}
// copy base class properties.
var objToCopyType = objToCopy.GetType();
foreach (PropertyInfo propertyInfo in objToCopyType.GetProperties())
{
// Get the correct property
PropertyInfo propertyInfoValue = objToCopyType.GetProperty(propertyInfo.Name);
// Get the value of the property
var value = objToCopyType.GetProperty(propertyInfo.Name).GetValue(objToCopy, null); // propertyInfoValue.GetValue(objToCopy, null);
// Create the ID for the dictionary, set to name/random string for easy viewing
string propertyKeyName = CreateSafeName(dataContainer, propertyInfo.Name);
// Create a property with the required name then add data
((IDictionary<String, Object>)dataContainer)[propertyInfo.Name] = new DataContainer(propertyInfo.Name, propertyInfo, propertyInfoValue, value);
}
return dataContainer;
}
When I look into the dynamic object I've created I see all the properties I want i.e. the Property Users contains a list of users. The next step is serialising this data which is where the error occurs.
dynamic serializableObject = GetSerializableProperties<T>(serializableObjectx);
var test = serializableObject as IDictionary<string, Object>;
var test2 = test.Values.ElementAt(2) as DataContainer; // This property contains a property that is causing the issue I believe
var obj = JsonConvert.SerializeObject(test2, Newtonsoft.Json.Formatting.Indented);
The error I get is:
Cannot evaluate expression because the current thread is in a stack overflow state.
I believe the code below this comment needs to be changed:
var value = objToCopyType.GetProperty(propertyInfo.Name).GetValue(objToCopy, null); // propertyInfoValue.GetValue(objToCopy, null);
If I get you right you are trying to serialize sharepoint objects? Most of the time it will end in a circulation.
SPGroup.Users -> SPUser.Groups -> SPGroup.Users -> ...
So the serializer will run in a infinite loop or a stack overflow. The better way will be building your own objects without some of the properties which leads to a circle.

Getting a PropertyInfo of a dynamic object

I have a library that is doing a bunch of reflection work relying on the PropertyInfo of the classes it receives (to get and set values).
Now I want to be able to work with dynamic objects, but I can't find how to get the PropertyInfo of a dynamic's properties. I've checked the alternatives, but for those I'd need to change everywhere I use PropertyInfo to get/set values.
dynamic entity = new ExpandoObject();
entity.MyID = 1;
// - Always null
PropertyInfo p = entity.GetType().GetProperty("MyID");
// - Always null
PropertyInfo[] ps = entity.GetType().GetProperties();
// - These are called everywhere in the code
object value = p.GetValue(entity);
p.SetValue(entity, value);
Is it possible to get or create a PropertyInfo somehow just to be able to use it's GetValue() and SetValue() on a dynamic object?
Under the covers an ExpandoObject is really just a dictionary. You can get at the dictionary just by casting it.
dynamic entity = new ExpandoObject();
entity.MyID = 1;
if(entity.GetType() == typeof(ExpandoObject))
{
Console.WriteLine("I'm dynamic, use the dictionary");
var dictionary = (IDictionary<string, object>)entity;
}
else
{
Console.WriteLine("Not dynamic, use reflection");
}
You could modify your Mapping method to check if the object being passed in is dynamic and route through a different path that just iterates over the keys of the dictionary.
https://dotnetfiddle.net/VQQZdy

How to get value of unknown properties (part solved already with reflection)

I have an existing c# application to modify and need to loop through an object with unknown properties and have half solved the problem with reflection.
I'm trying to populate a dictionary with the property name and the property value. The code is below and I've given a description of what I need in between the ***s
This is an MVC5 project
private Dictionary<string, string> StoreUserDetails ()
{
var userDetails = new Dictionary<string, string>();
foreach (var userItem in UserItems)
{
var theType = userItem.GetType();
var theProperties = theType.GetProperties();
foreach (var property in theProperties)
{
userDetails.Add(property.Name, ***value of userItem property with this property name***);
}
}
return userDetails;
}
Many thanks in advance for your help.
try this
foreach (var property in theProperties)
{
var userItemVal = property.GetValue(userItem, null);
userDetails.Add(property.Name, userItemVal.ToString());
}
What you're looking for is the PropertyInfo.GetValue() method:
https://msdn.microsoft.com/en-us/library/b05d59ty%28v=vs.110%29.aspx
Example
property.GetValue(userItem, null);
Syntax
public virtual Object GetValue(
Object obj,
Object[] index
)
Parameters
obj
Type: System.Object
The object whose property value will be returned.
index
Type: System.Object[]
Optional index values for indexed properties. The indexes of indexed properties are zero-based. This value should be null for non-indexed properties.
Return Value
Type: System.Object
The property value of the specified object.
this is how you can do it. (by the way, your code might error out on "dictionary key not being unique" since the second userItem will try to add the same property name to the dictionary. you might need a List<KeyValuePair<string, string>>)
foreach (var property in theProperties)
{
// gets the value of the property for the instance.
// be careful of null values.
var value = property.GetValue(userItem);
userDetails.Add(property.Name, value == null ? null : value.ToString());
}
and by the way, if you're in MVC context, you could take a reference to System.Web.Routing and use the following snippet.
foreach (var userItem in UserItems)
{
// RVD is provided by routing framework and it gives a dictionary
// of the object property names and values, without us doing
// anything funky.
var userItemDictionary= new RouteValueDictionary(userItem);
}

Object does not match target type PropertyInfo SetValue - one class to another

So I have 2 classes, both have identical Property names. One class contains different variables: int, strings, bool and DateTime The second class contains only 1 int and the rest are all strings.
Now I want to loop through all the properties, get the value from class1, encrypt that data and save it as a string in obj2, then return it to the main form (to save it in a database later).
public PersoonEncrypted EncryptPersonClass(Class1 object1)
{
PersoonEncrypted persEncrypt = new PersoonEncrypted(); //second class obj
Type type = object1.GetType();
PropertyInfo[] properties = type.GetProperties();
Type type2 = persEncrypt.GetType();
PropertyInfo[] properties2 = type.GetProperties();
foreach (var bothProperties in properties.Zip(properties2, (obj1, obj2) => new { Obj1 = obj1, Obj2 = obj2 }))
{
string value = "";
value = bothProperties.Obj1.GetValue(object1) as string;
if (!string.IsNullOrWhiteSpace(value))
{
string encryptValue = Encrypt(value);
if ((bothProperties.Obj2 != null) && (bothProperties.Obj2.PropertyType == typeof(string)))
{ //!= null check has no effect at all
bothProperties.Obj2.SetValue(persEncrypt, encryptValue, null); //errorLine
}
}
}
return persEncrypt;
}
That is what I came up with until now.
I have, of course, searched for other solutions like this one. This, after applying some own changes, didn't return any errors, but it didn't save any encrypted strings into the class persEncrypt. What I concluded was, from that test, is that it was testing if the value in the second class(persEncrypt in my example) from the particular property was null, while it shouldn't do that, it should make a new instance of that variable and save it in the object class, but removing that check gave me the same error.
you're just .Zip-ing the two lists of PropertyInfo objects, which simply iterates through both lists and doesn't check or sort for any sort of matching. This could result in erroneous behavior depending on the order in which properties appear - consider using a .Join instead to match property names.
This code doesn't check for an indexer on the property before attempting to assign to it without one - any indexed property which is of type string will make it to this point and then throw an exception when you try to set it.
Because this code is calling into Properties, there's the possibility an exception is being thrown by the code of the Property itself. This is where a StackTrace from your exception could reveal much more about what's happening.
Your code also checks for a property of type string directly - when using reflection you should use IsAssignableFrom instead in order to allow for inherited types, though that is unlikely the issue in this one case.

Get PropertyInfo value

I'm trying to get the value from a PropertyInfo[], but I can't get it to work:
foreach (var propertyInfo in foo.GetType().GetProperties())
{
var value = propertyInfo.GetValue(this, null);
}
Exception: Object does not match target type.
Isn't this how it's supposed to be done?
You're trying to get properties from this when you originally fetched the PropertyInfos from foo.GetType(). So this would be more appropriate:
var value = propertyInfo.GetValue(foo, null);
That's assuming you want to effectively get foo.SomeProperty etc.
You're getting that exception because this isn't the same type as foo.
You should make sure you're getting the properties for the same object that you're going to try to get the value from. I'm guessing from your code that you're expecting this to be foo inside the scope of the loop (which isn't the case at all), so you need to change the offending line to:
var value = propertyInfo.GetValue(foo, null);
You are processing properties declared in foo's type, but try to read their values from this, which apparently isn't of the same type.

Categories

Resources