I'm trying to set value to properties in many objects.
I've a function that receive 2 parameters MyStructuredObjects and MyObject
MyStructuredObjects has a list of MyObjects.
This Function is a re-factory to remove a lot of 'if's.
I'd like to use ever the same object because the function it is used in a loop.If it is possible.
I've getting ever the exception 'Object does not match target'.
Sorry posting this, but I don't found problems like this, using List inside a Object structure.
Take a look :
public class MyStructuredObjects
{
public List<MyObject1> Object1 { get; set; }
public List<MyObject2> Object2 { get; set; }
public List<MyObject3> Object3 { get; set; }
public List<MyObject4> Object4 { get; set; }
public List<MyObject5> Object5 { get; set; }
}
private void SetValuesToObjectsToIntegrate<T>(ref MyStructuredObjects returnedObject, T obj)
{
Type t = obj.GetType();
var propertyInfo = new ObjectsToIntegrate().GetType().GetProperties();
var instance = Activator.CreateInstance(t);
foreach (var item in returnedObject.GetType().GetProperties())
{
var itemType = item.PropertyType;
if (t == itemType) // PASSING BY HERE OK , it finds the same type :P
{
item.SetValue(t, Convert.ChangeType(obj, item.PropertyType), null);
}
}
}
Update: The code should be:
item.SetValue(instance, Convert.ChangeType(obj, item.PropertyType), null);
I think I understand what you're trying to do.
It appears that you're trying to set properties like this:
var o2 = new List<MyObject2>();
var mso = new MyStructuredObjects();
SetValuesToObjectsToIntegrate(ref mso, o2);
So that mso will have its property Object2 set because the type of o2 matches the property type.
If that's the case, then you only need this code:
private void SetValuesToObjectsToIntegrate<T>(MyStructuredObjects returnedObject, T obj)
{
foreach (var propertyInfo in typeof(MyStructuredObjects).GetProperties())
{
if (typeof(T) == propertyInfo.PropertyType)
{
propertyInfo.SetValue(returnedObject, obj, null);
}
}
}
There's no need to pass MyStructuredObjects returnedObject by ref as you're not changing the instance of returnedObject.
Use this to call this code:
var o2 = new List<MyObject2>();
var mso = new MyStructuredObjects();
SetValuesToObjectsToIntegrate(mso, o2);
After this call I now get:
Related
I'm trying to get the value of a custom class with List<T> properties, however it throws an exception (Object does not match target type.).
I want to check first if the value is Null if not then process the value.
Model:
public class CustomModel
{
public List<Foo> FooList { get; set; }
public List<Bar> BarList { get; set; }
}
Codes for processing the model data:
public class Result<T>
{
private readonly T _model;
public Result(T model)
{
_model = model;
}
private CustomObject CreateSomething(T model)
{
var obj = new CustomObject();
var type = model.GetType();
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.PropertyType.IsGenericType &&
typeof(List<>).IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
{
//this throws an error
var testList = property.GetValue(this, new object[] { });
//processed value will be passed to object
//some codes here after getting the property value
}
}
return obj;
}
}
How do I get the value so I can process them?
Is it a typo? The property is read from this instead of the model:
var testList = property.GetValue(model, new object[] { });
^^^^^
You should make the List<> to a generic type with MakeGenericType().
Something like:
var listType = typeof(List<>).MakeGenericType(new[]{typeof(T)});
if (property.PropertyType.IsGenericType
&& listType.IsAssignableFrom(property.PropertyType.GetGenericTypeDefinition()))
More info on MakeGenericType: https://msdn.microsoft.com/en-us/library/system.type.makegenerictype
var testList = property.GetValue(this, new object[] { });
Are you sure you passing the right object instance? this here?
It should be var testList = property.GetValue(FooList, new object[] { }); <-- FooList
I have a class which normally contains Fields, Properties. What i want to achieve is instead of this:
class Example
{
public string Field = "EN";
public string Name { get; set; }
public int? Age { get; set; }
public List<string> A_State_of_String { get; set; }
}
public static void Test()
{
var c1 = new Example
{
Name = "Philip",
Age = null,
A_State_of_String = new List<string>
{
"Some Strings"
}
};
var c2 = new Example();
//Instead of doing that
c2.Name = string.IsNullOrEmpty(c1.Name) ? "" : c1.Name;
c2.Age = c1.Age ?? 0;
c2.A_State_of_String = c1.A_State_of_String ?? new List<string>();
//Just do that
c1.CopyEmAll(c2);
}
What i came up with but doesn't work as expected.
public static void CopyEmAll(this object src, object dest)
{
if (src == null) {
throw new ArgumentNullException("src");
}
foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(src)) {
var val = item.GetValue(src);
if (val == null) {
continue;
}
item.SetValue(dest, val);
}
}
Problems:
Although i checked for null, it seems to bypass it.
Doesn't seem to copy Fields.
Notes:
I don't want to use AutoMapper for some technical issues.
I want the method to copy values and not creating new object. [just mimic the behavior i stated in the example]
I want the function to be recursive [if the class contains another classes it copies its values too going to the most inner one]
Don't want to copy null or empty values unless i allow it to.
Copies all Fields, Properties, or even Events.
Based on Leo's answer, but using Generics and copying also the fields:
public void CopyAll<T>(T source, T target)
{
var type = typeof(T);
foreach (var sourceProperty in type.GetProperties())
{
var targetProperty = type.GetProperty(sourceProperty.Name);
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
foreach (var sourceField in type.GetFields())
{
var targetField = type.GetField(sourceField.Name);
targetField.SetValue(target, sourceField.GetValue(source));
}
}
And then just:
CopyAll(f1, f2);
You can use serialization to serialize object A and deserialize as object B - if they have very same structure, you can look here for object deep copy.
Deep cloning objects
I know you don't want to use Automapper, but if the types have only SIMILAR structure, you should maybe use Automapper which is based on reflection. You can download a nuget and find some information here:
https://www.nuget.org/packages/AutoMapper/
your code then will look like
public TOutput CopyAll<TInput, TOutput>(TInput input)
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<TInput, TOutput>());
IMapper mapper = config.CreateMapper();
return mapper.Map<TOutput>(vstup);
}
i am trying to "upcast" a Entity. The Entity B have just a few more propeties.
Entities:
public class A
{
public String Name { get; set; }
}
public class B : A
{
public String ForeName { get; set; }
}
I am trying to conver the value of A.Name into B.Name programmatically.
I´ve written a little function for that case:
public static T Upcast<T>(Type typeOf, Object obj) where T : new()
{
var target = new T();
var props = obj.GetType().GetProperties();
var targetProps = target.GetType().GetProperties();
foreach (var prop in props)
{
foreach (var tp in targetProps)
{
if (prop.Name.Equals(tp.Name))
{
var val = prop.GetValue(props, null);
tp.SetValue(null, val, null);
}
}
}
return target;
}
In this case: my target is class B and my obj is class A
But it fires a Exception in the second loop:
var val = prop.GetValue(props, null);
The Exception "Object does not match target type".
i am calling the function on a normal way:
static void Main(string[] args)
{
var a = new A {Name = "Smith"};
var resp = Upcast<B>(a.GetType(), a);
Console.ReadLine();
}
Replace prop.GetValue(props, null); with prop.GetValue(obj, null);
It gives me "Smith".
You must call prop.GetValue(...); with the target object as argument, not with the property collection:
prop.GetValue(obj, null);
Starting with .NET 4.5 you can write
var val = prop.GetValue(obj);
You are trying the read the value out of an instance of PropertyInfo class. But what you want is to read the value out of your instance of A.
Another hint, for cleaner code:
Don't pass the type of A as argument. If you pass an instance of A, your method can make obj.GetType().
But: why are you doing that???
I have a generic class, and an object value where obj.GetType().GetGenericTypeDefinition() == typeof(Foo<>).
class Foo<T>
{
public List<T> Items { get; set; }
}
How do I get the value of Items from obj? Remember, obj is an Object, I can't cast obj as Foo because I don't know what T is.
I was hoping to use reflection for this, but each time I do GetProperty("Items") it returns null. However, if someone knows a good way to do this without reflection, by all means.
Let's say my code looks like this:
//just to demonstrate where this comes from
Foo<int> fooObject = new Foo<int>();
fooObject.Items = someList;
object obj = (object)fooObject;
//now trying to get the Item value back from obj
//assume I have no idea what <T> is
PropertyInfo propInfo = obj.GetType().GetProperty("Items"); //this returns null
object itemValue = propInfo.GetValue(obj, null); //and this breaks because it's null
You should be able to use:
Type t = obj.GetType();
PropertyInfo prop = t.GetProperty("Items");
object list = prop.GetValue(obj);
You will not be able to cast as a List<T> directly, of course, as you don't know the type T, but you should still be able to get the value of Items.
Edit:
The following is a complete example, to demonstrate this working:
// Define other methods and classes here
class Foo<T>
{
public List<T> Items { get; set; }
}
class Program
{
void Main()
{
//just to demonstrate where this comes from
Foo<int> fooObject = new Foo<int>();
fooObject.Items = new List<int> { 1, 2, 3};
object obj = (object)fooObject;
//now trying to get the Item value back from obj
//assume I have no idea what <T> is
PropertyInfo propInfo = obj.GetType().GetProperty("Items"); //this returns null
object itemValue = propInfo.GetValue(obj, null);
Console.WriteLine(itemValue);
// Does not print out NULL - prints out System.Collections.Generic.List`1[System.Int32]
IList values = (IList)itemValue;
foreach(var val in values)
Console.WriteLine(val); // Writes out values appropriately
}
}
#ReedCopsey is absolutely correct, but in case you're really asking the question "How do I fish out the generic details of a type?", here's some "Fun with Reflection":
public void WhatsaFoo(object obj)
{
var genericType = obj.GetType().GetGenericTypeDefinition();
if(genericType == typeof(Foo<>))
{
// Figure out what generic args were used to make this thing
var genArgs = obj.GetType().GetGenericArguments();
// fetch the actual typed variant of Foo
var typedVariant = genericType.MakeGenericType(genArgs);
// alternatively, we can say what the type of T is...
var typeofT = obj.GetType().GetGenericArguments().First();
// or fetch the list...
var itemsOf = typedVariant.GetProperty("Items").GetValue(obj, null);
}
}
Something like this should do the trick:
var foo = new Foo<int>();
foo.Items = new List<int>(new int[]{1,2,3});
// this check is probably not needed, but safety first :)
if (foo.GetType().GetProperties().Any(p => p.Name == "Items"))
{
var items = foo.GetType().GetProperty("Items").GetValue(foo, null);
}
You have to use System.Reflection namespace to execute the program successfully.
This program gives you Property Name and Value of any Generic Class
You can check this code fiddle on C# Online Rexter Tool Compiler at
using System;
using System.Reflection;
namespace GenericPropertyExample
{
//Declaring a Sample Class
public class class1
{
public string prop1 { get; set; }
public string prop2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
//Creating Class Object
class1 objClass1 = new class1 { prop1 = "value1", prop2 = "value2" };
//Passing Class Object to GenericPropertyFinder Class
GenericPropertyFinder<class1> objGenericPropertyFinder = new GenericPropertyFinder<class1>();
objGenericPropertyFinder.PrintTModelPropertyAndValue(objClass1);
Console.ReadLine();
}
//Declaring a Generic Handler Class which will actually give Property Name,Value for any given class.
public class GenericPropertyFinder<TModel> where TModel : class
{
public void PrintTModelPropertyAndValue(TModel tmodelObj)
{
//Getting Type of Generic Class Model
Type tModelType = tmodelObj.GetType();
//We will be defining a PropertyInfo Object which contains details about the class property
PropertyInfo[] arrayPropertyInfos = tModelType.GetProperties();
//Now we will loop in all properties one by one to get value
foreach (PropertyInfo property in arrayPropertyInfos)
{
Console.WriteLine("Name of Property is\t:\t" + property.Name);
Console.WriteLine("Value of Property is\t:\t" + property.GetValue(tmodelObj).ToString());
Console.WriteLine(Environment.NewLine);
}
}
}
}
}
Hey guys ive been struggeling with the same issue with generic typs and finally found the solution that gets the value
--------Small code snippet of the method that does the trick ------------------
public void printFields()
{
// Is the list empty
if (this.list_.Count == 0)
{
//Y => Forced exit no object info
return;
}
try
{
// Get first item from list
T item = this.list_[0];
// Get the type of object
//**Type thisType = item.GetType();
// Get array of all fields
FieldInfo[] thisFieldInfo = item.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
// Loop through all fields and show its info
for (int ix = 0; ix < thisFieldInfo.Length; ix++)
{
// Get Field value
String strVal = thisFieldInfo[ix].GetValue(item).ToString();
// Display item
Console.WriteLine("'{0}' is a {1} and has value {2}", thisFieldInfo[ix].Name, thisFieldInfo[ix].FieldType, strVal);
}
}
catch (SecurityException e)
{
Console.WriteLine("Exception: " + e.Message);
}
}
I'm writing my own method to convert an object graph to a custom object since the JavaScriptSerializer fires errors on null values.
So this is what I have so far:
internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
T generic = (T)Activator.CreateInstance<T>();
Type resType = typeof(T);
foreach (PropertyInfo pi in resType.GetProperties())
{
object outObj = new object();
if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
{
Type outType = outObj.GetType();
if (outType == pi.PropertyType)
{
pi.SetValue(generic, outObj, null);
}
}
}
return generic;
}
Now the pi.SetValue() method runs, and doesn't fire an error but when I look at the properties of generic, it's still the same as it was before hand.
The first property it goes through is a boolean so the values end up like this
generic = an object of type MyCustomType
generic.property = false
outObj = true
pi = boolean property
outType = boolean
Then after the SetValue method runs, generic.property is still set to false.
PropertyInfo.SetValue/GetValue worked with struct with accurate using
struct Z
{
public int X { get; set; }
}
Z z1 = new Z();
z1.GetType().GetProperty("X").SetValue(z1, 100, null);
Console.WriteLine(z1.X); //z1.X dont changed
object z2 = new Z();
z2.GetType().GetProperty("X").SetValue(z2, 100, null);
Console.WriteLine(((Z)z2).X); //z2.x changed to 100
Z z3 = new Z();
object _z3 = z3;
_z3.GetType().GetProperty("X").SetValue(_z3, 100, null);
z3 = (Z)_z3;
Console.WriteLine(z3.X); //z3.x changed to 100
Correct way to change struct:
box struct
change property of boxed struct
assign boxed struct to source
Found the answer. Apparently, PropertyInfo.SetValue() and PropertyInfo.GetValue() do not work for structures, only classes.
MyCustomType was unfortunately a struct, so changing this to a class made it work.
The 3rd reply in this thread states why structures do not work and classes do.
EDIT: It does work with structs, see the marked answer.
So I took your method and made a unit test of it:
class PropertySetTest
{
static readonly Type resType = typeof(Car);
internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
T generic = (T)Activator.CreateInstance<T>();
foreach (PropertyInfo pi in resType.GetProperties())
{
//No need to new() this
object outObj; // = new object();
if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
{
Type outType = outObj.GetType();
if (outType == pi.PropertyType)
{
pi.SetValue(generic, outObj, null);
}
}
}
return generic;
}
[Test]
public void Test()
{
var typeData = new Dictionary<String, Object> {{"color", "Blue"}};
var myCar = ParseObjectGraph<Car>(typeData);
Assert.AreEqual("Blue", myCar.Color);
}
}
internal class Car
{
public String Color { get; set; }
}
This passes. Can you make it not pass in the way that you are seeing?
EDIT: With your struct, it is only marginally more complicated. See Jon Skeet's answer here regarding what's going on. As for the working code:
class PropertySetTest
{
static readonly Type resType = typeof(Car);
internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
Object generic = Activator.CreateInstance<T>();
foreach (var pi in resType.GetProperties())
{
//No need to new() this
object outObj; // = new object();
if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
{
var outType = outObj.GetType();
if (outType == pi.PropertyType)
pi.SetValue(generic, outObj, null);
}
}
return (T)generic;
}
[Test]
public void Test()
{
var typeData = new Dictionary<String, Object> {{"color", "Blue"}};
var myCar = ParseObjectGraph<Car>(typeData);
Assert.AreEqual("Blue", myCar.Color);
}
}
internal struct Car
{
public String Color { get; set; }
}