I'm trying to set a property of an object in a class, but the error says Object does not match target type.
FieldInfo dControl = window.GetType().GetField("dControl", BindingFlags.NonPublic | BindingFlags.Instance);
if (dControl == null) { Debug.Log ("dControl is null"); return;}
Type typeDC = dControl.FieldType;
PropertyInfo inPreviewMode = typeDC.GetProperty("InPreviewMode", BindingFlags.Public | BindingFlags.Instance);
if (inPreviewMode == null) { Debug.Log ("dControl.InPreviewMode is null"); return;}
bool value = false;
inPreviewMode.SetValue(dControl, value, null);
This is the property I'm trying to access:
public class DControl : TimeArea
{
public bool InPreviewMode
{
get
{
return dState.IsInPreviewMode;
}
set
{
if (cutscene != null)
{
...
}
}
dState.IsInPreviewMode = value;
}
...
}
Help is appreciated.
The first parameter of SetValue is the instance for which to set the value on. ie, it is expecting an instance of DControl - your code passes it an instance of FieldInfo.
So you might have to get that instance via reflection:
DControl ctrl = (DControl)dControl.GetValue(window);
And then pass that to the set value
inPreviewMode.SetValue(ctrl, value, null);
Related
I have the following code to compare two collections to one another...
//code invocation
CollectionComparer comp = new CollectionComparer("name", "ASC");
this.InnerList.Sort(comp);
class
public class CollectionComparer : IComparer
{
private String _property;
private String _order;
public CollectionComparer(String Property, String Order)
{
this._property = Property;
this._order = Order;
}
public int Compare(object obj1, object obj2)
{
int returnValue;
Type type = obj1.GetType();
PropertyInfo propertie1 = type.GetProperty(_property); // returns null here
Type type2 = obj2.GetType();
PropertyInfo propertie2 = type2.GetProperty(_property); // returns null here
object finalObj1 = propertie1.GetValue(obj1, null); // Null Reference Exception thrown here, because propertie1 is null
object finalObj2 = propertie2.GetValue(obj2, null);
IComparable Ic1 = finalObj1 as IComparable;
IComparable Ic2 = finalObj2 as IComparable;
if (_order == "ASC")
{
returnValue = Ic1.CompareTo(Ic2);
}
else
{
returnValue = Ic2.CompareTo(Ic1);
}
return returnValue;
}
}
The code seems to work fine, except when I try to sort a property called "name". When comparing that property both the variables propertie1 and propertie2 are null, and the code throws an exception because of that.
So my question is how to use reflection to get the value of a property with the name of "name"?
By the way, is _property variable set?
How about this extension method:
public static object GetProperty(this object instance, string name)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (name == null)
throw new ArgumentNullException("name");
Type type = instance.GetType();
PropertyInfo property = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
if (property == null)
throw new InvalidOperationException(string.Format("Type {0} does not have a property {1}", type, name));
object result = property.GetValue(instance, null);
return result;
}
Ok, I figured it out... I guess uppercase counts when doing reflection...
I needed to change the code invocation to...
//code invocation
CollectionComparer comp = new CollectionComparer("Name", "ASC");
this.InnerList.Sort(comp);
As the property was actually called "Name" and not "name"
I have following piece of code:
ClassName class = new ClassName();
var getValue = GetPrivateProperty<BaseClass>(class, "BoolProperty");
public static T GetPrivateProperty<T>(object obj, string name)
{
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
PropertyInfo field = typeof(T).GetProperty(name, flags);
return (T)field.GetValue(obj, null);
}
Now when I get an InvalidCastException in the return statement that he can not convert the object with type System.Boolean to the type ClassName.
BaseClass has the property. ClassName inherits from BaseClass. In have to access all properties from the "ClassName" Class. Since this property is private, I have to access it directly over the BaseClass. This works but I crashes because the property has the return value boolean.
Thanks!
You got the property of type T and the return value should also be of type T? I don't believe that.
Maybe this will help:
var getValue = GetPrivateProperty<bool>(class, "BoolProperty");
public static T GetPrivateProperty<T>(object obj, string name)
{
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
PropertyInfo field = null;
var objType = obj.GetType();
while (objType != null && field == null)
{
field = objType.GetProperty(name, flags);
objType = objType.BaseType;
}
return (T)field.GetValue(obj, null);
}
Please see the changes of <BaseClass> to <bool> and typeof(T).GetProperty to obj.GetType().GetProperty.
I am using reflection to set a property from within a reflected property. I have to use reflection as I don't know what the type the child propery will be, but each time I get System.Target.TargetException (on the prop.SetValue) prop is pointing to the correct property
I can find lot of examples of the SetValue, the problem that I am having, is I expect related to the fact that selectSubProcess is a PropertyInfo rather than a actual class
PropertyInfo selectedSubProcess = process.GetProperty(e.ChangedItem.Parent.Label);
Type subType = selectedSubProcess.PropertyType;
PropertyInfo prop = subType.GetProperty(e.ChangedItem.Label + "Specified");
if (prop != null)
{
prop.SetValue(process, true, null);
}
It looks like process is "Type", not an instance of an object. in the line
prop.SetValue(process, true, null);
you need an instance of an object to set, not a Type.
Use "GetValue" to get an instance of the object you care about:
public void test()
{
A originalProcess = new A();
originalProcess.subProcess.someBoolean = false;
Type originalProcessType = originalProcess.GetType();
PropertyInfo selectedSubProcess = originalProcessType.GetProperty("subProcess");
object subProcess = selectedSubProcess.GetValue(originalProcess, null);
Type subType = selectedSubProcess.PropertyType;
PropertyInfo prop = subType.GetProperty("someBoolean");
if (prop != null)
{
prop.SetValue(subProcess, true, null);
}
MessageBox.Show(originalProcess.subProcess.someBoolean.ToString());
}
public class A
{
private B pSubProcess = new B();
public B subProcess
{
get
{
return pSubProcess;
}
set
{
pSubProcess = value;
}
}
}
public class B
{
private bool pSomeBoolean = false;
public bool someBoolean
{
get
{
return pSomeBoolean;
}
set
{
pSomeBoolean = true;
}
}
}
i have used the following code to change the current value for the current field value as
FieldInfo connectionStringField = GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
connectionStringField.SetValue(this, connectionString);
but my query is to get current value of connectionstringfied...
i tried the below code as
getvalue(obj ss);
waiting for your valuable esponses
it throws me null values
If connectionStringField has found the field (i.e. it is in the base type and is called "_sqlConnectionString", then it should just be:
string connectionString = (string)connectionStringField.GetValue(this);
?
However, using reflection to talk to non-public fields is... unusual.
public static string GetPropertyValue<T>(this T obj, string parameterName)
{
PropertyInfo[] property = null;
Type typ = obj.GetType();
if (listPropertyInfo.ContainsKey(typ.Name))
{
property = listPropertyInfo[typ.Name];
}
else
{
property = typ.GetProperties();
listPropertyInfo.TryAdd(typ.Name, property);
}
return property.First(p => p.Name == parameterName).GetValue(obj, null).ToString();
}
listPropertyInfo is a cache to avoid reflection performance issue
public static void SetPropertyValue<T>(this T obj, string parameterName, object value)
{
PropertyInfo[] property = null;
Type typ = obj.GetType();
if (listPropertyInfo.ContainsKey(typ.Name))
{
property = listPropertyInfo[typ.Name];
}
else
{
property = typ.GetProperties();
listPropertyInfo.TryAdd(typ.Name, property);
}
if (value == DBNull.Value)
{
value = null;
}
property.First(p => p.Name == parameterName).SetValue(obj,value, null);
}
I used the same trick for setters
I am trying to set a value to a Nested Property of Class dynamically using reflection. Could anyone help me to do this.
I am having a class Region like below.
public class Region
{
public int id;
public string name;
public Country CountryInfo;
}
public class Country
{
public int id;
public string name;
}
I have a Oracle Data reader to provide the Values from the Ref cursor.
which will give me as
Id,name,Country_id,Country_name
I could able to assign the values to the Region.Id, Region.Name by below.
FieldName="id"
prop = objItem.GetType().GetProperty(FieldName, BindingFlags.Public | BindingFlags.Instance);
prop.SetValue(objItem, Utility.ToLong(reader_new[ResultName]), null);
And for the Nested Property I could able to do the assign values to the as below by creating a Instance by reading the Fieldname.
FieldName="CountryInfo.id"
if (FieldName.Contains('.'))
{
Object NestedObject = objItem.GetType().GetProperty(Utility.Trim(FieldName.Split('.')[0]), BindingFlags.Public | BindingFlags.Instance);
//getting the Type of NestedObject
Type NestedObjectType = NestedObject.GetType();
//Creating Instance
Object Nested = Activator.CreateInstance(typeNew);
//Getting the nested Property
PropertyInfo nestedpropinfo = objItem.GetType().GetProperty(Utility.Trim(FieldName.Split('.')[0]), BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] nestedpropertyInfoArray = nestedpropinfo.PropertyType.GetProperties();
prop = nestedpropertyInfoArray.Where(p => p.Name == Utility.Trim(FieldName.Split('.')[1])).SingleOrDefault();
prop.SetValue(Nested, Utility.ToLong(reader_new[ResultName]), null);
Nestedprop = objItem.GetType().GetProperty(Utility.Trim(FieldName.Split('.')[0]), BindingFlags.Public | BindingFlags.Instance);
Nestedprop.SetValue(objItem, Nested, null);
}
The above assign values to Country.Id.
But Since I am creating instance each and every time I could not able to get the previous Country.Id value if I go for the Next Country.Name.
Could anybody tell could to assign values to the objItem(that is Region).Country.Id and objItem.Country.Name. Which means how to assign values to the Nested Properties instead of creating instance and assigning everytime.
Thanks in advance.!
You should be calling PropertyInfo.GetValue using the Country property to get the country, then PropertyInfo.SetValue using the Id property to set the ID on the country.
So something like this:
public void SetProperty(string compoundProperty, object target, object value)
{
string[] bits = compoundProperty.Split('.');
for (int i = 0; i < bits.Length - 1; i++)
{
PropertyInfo propertyToGet = target.GetType().GetProperty(bits[i]);
target = propertyToGet.GetValue(target, null);
}
PropertyInfo propertyToSet = target.GetType().GetProperty(bits.Last());
propertyToSet.SetValue(target, value, null);
}
Get Nest properties e.g., Developer.Project.Name
private static System.Reflection.PropertyInfo GetProperty(object t, string PropertName)
{
if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
if (PropertName.Split('.').Length == 1)
return t.GetType().GetProperty(PropertName);
else
return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1]);
}
Expanding on Jon Skeets answer, if the value you're getting is null and you want to create an object for that type:
public void SetProperty(string compoundProperty, object target, object value)
{
var bits = compoundProperty.Split('.');
for (var i = 0; i < bits.Length - 1; i++) {
var propertyToGet = target.GetType().GetProperty(bits[i]);
var propertyValue = propertyToGet.GetValue(target, null);
if (propertyValue == null) {
propertyValue = Activator.CreateInstance(propertyToGet.PropertyType);
propertyToGet.SetValue(target, propertyValue);
}
target = propertyToGet.GetValue(target, null);
}
var propertyToSet = target.GetType().GetProperty(bits.Last());
propertyToSet.SetValue(target, value, null);
}
Expanding on Luke Garrigan Answer:
If you want to have it working also with non lists too:
public void SetProperty(string compoundProperty, object target, object value)
{
var bits = compoundProperty.Split('.');
if(bits == null) bits = new string[1]{compoundProperty};
for (var i = 0; i < bits.Length - 1; i++) {
var propertyToGet = target.GetType().GetProperty(bits[i]);
var propertyValue = propertyToGet.GetValue(target, null);
if (propertyValue == null) {
propertyValue = Activator.CreateInstance(propertyToGet.PropertyType);
propertyToGet.SetValue(target, propertyValue);
}
target = propertyToGet.GetValue(target, null);
}
var propertyToSet = target.GetType().GetProperty(bits.Last());
propertyToSet.SetValue(target, value, null);
}