Get PropertyInfo value - c#

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.

Related

C# check if type of PropertyInfo is primitive

Is it possible to check if the type, which is stored in PropertyInfo, is primitive?
For example I want to do this:
// from and to are both objects declared in the parameters.
Type fType = from.GetType();
Type tType = to.GetType();
PropertyInfo[] fmpi = fType.GetProperties();
PropertyInfo[] tmpi = tType.GetProperties();
foreach(var pi in tmpi)
{
if (pi.CanWrite)
{
var fpi = fmpi.SingleOrDefault(item => item.Name.ToLower() == pi.Name.ToLower());
if (pi.GetType().IsPrimitive || pi.GetType() == typeof(string))
{
pi.SetValue(to, fpi.GetValue(from, null));
}
}
}
Whenever I execute this code It doesn't go through the if statemenet. The main reason is that whenever I do pi.GetType() it says that it's a PropertyInfo. This is quite obvious since it's declared as a PropertyInfo. But I hope you get the idea.
I have also discovered that pi.PropertyType.Name contains the name of the actual type of the property. Is there anyway I can execute IsPrimitive on this property? If not, is there any work around which let's me do something like this?
I checked out How To Test if Type is Primitive but in this situation the user is using a direct type and I'm using PropertyInfo.
The main reason is that whenever I do pi.GetType() it says that it's a PropertyInfo.
You should use PropertyType property of PropertyInfo instead of using GetType() method.
Excerpt from documentation:
Gets the type of this property.
So instead of
pi.GetType().IsPrimitive
use this
pi.PropertyType.IsPrimitive

How can I create instance of a type and set member values by name?

I read an XML for a list of commands, where each command is like this one
<Read Id="3" LocationId="21"/>
or
<Transform transformId="45" source="string"/>
And in my XML deserializer I'm at this point where I'm setting up all the command objects and getting them ready for execution.
Type cType = Assembly.GetExecutingAssembly().GetType("Processing." + command.Name.ToString());
ICommand commandObject = Activator.CreateInstance(cType);
When I use the Activator.CreateInstance, is there a way to assign the members called 'Id' and 'LocationId' the values 3 and 21? I don't know in advance which ICommand I am on and each ICommand has different members (except they all share only one method)
Like maybe (pseudocode)
commandObject = Activator.CreateInstance(cType);
foreach( XMLAttribute attribute in Element){
commandObject <- SetClassMember(attribute.Name, attribute.value)
}
Dynamic variable types are resolved in runtime already, if you know that your commands will always contain the Id and LocationId properties you can do like:
dynamic commandObject = Activator.CreateInstance(cType);
commandObject.Id = 3;
commandObject.LocationId = 21;
Otherwise you have to use reflection to check if it exists first:
PropertyInfo prop = commandObject.GetType().GetProperty("Id");
if(null != prop && prop.CanWrite)
{
prop.SetValue(commandObject, 3, null);
}
Since there is no way to know which properties you have to set until runtime, I can't think of a better way other than plain reflection to set those. A naive implementation could be somewhat like this:
object commandObject = Activator.CreateInstance(cType);
cType.GetProperty("Id").SetValue(commandObject, 3, null);
cType.GetProperty("LocationId").SetValue(commandObject, 3, null);
This will set properties according to your sample. To make it generic you can run it in a loop for each property (adapting to the last edit):
object commandObject = Activator.CreateInstance(cType);
foreach(XMLAttribute attribute in Element){
cType.GetProperty(attribute.Name).SetValue(commandObject, attribute.value, null);
}
A few caveats. It doesn't checks anything at runtime, since the types are dynamically determined properties need to exist according to the XML structure, so this code may as well throw a NullReferenceException anytime is types are wrong. You could do a bit of validation inside the reflection call and react more appropriately, though. Unfortunately, there is no way to verify this at compile time.

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.

Obtain members' name and value

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?

Passing a property into a method to change that property

Not sure if this is possible, but here is what I am trying to do:
I want to have a dictionary that contains a mapping of a column index to a property name used to populate that index.
In my code I will loop through an array if strings and use the dictionary to look up which column it should map to.
My end result code would look like:
for(int index = 0; index < fields.Length)
{
fieldPropertyMapping[index] = StripQuotes(fields[index]);
}
To do what you're asking specifically, you'll have to use reflection (as you tagged your question) to do this. Have a look at the PropertyInfo class. I'm not entirely certain what your code is doing, but a general example of reflectively setting a property value would be:
object targetInstance = ...; // your target instance
PropertyInfo prop = targetInstance.GetType().GetProperty(propertyName);
prop.SetValue(targetInstance, null, newValue);
You could, however, pass an Action<T> instead, if you know the property at some point in the code. For example:
YourType targetInstance = ...;
Action<PropertyType> prop = value => targetInstance.PropertyName = value;
... // in your consuming code
prop(newValue);
Or, if you know the type when you call it but you don't have the instance, you could make it an Action<YourType, PropertyType>. This also would prevent creating a closure.
Action<YourType, PropertyType> prop = (instance, value) => instance.PropertyName = value;
... // in your consuming code
prop(instance, newValue);
To make this fully generic ("generic" as in "non-specific", not as in generics), you'll probably have to make it an Action<object> and cast it to the proper property type within the lambda, but this should work either way.
You have a couple of choices:
Use reflection. Store and pass a PropertyInfo object into the method and set it's value through reflection.
Create an ActionDelegate with a closure to that property and pass that into the method.
you can use reflection to get the properties for a class:
var properties = obj.GetType().GetProperties();
foreach (var property in properties)
{
//read / write the property, here... do whatever you need
}

Categories

Resources