Refelection Converting Property into another instance - c#

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???

Related

SetValue Method throw Exception when using reflection

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:

Trying to get MetadataType by reflect not giving same results if I call the class directly

I'm trying to setup a T4 template that will loop through entity objects and ignore certain navigation properties based on an custom attribute I setup in the class' metdata data.
Here's the setup of the metadata tag
[MetadataType(typeof(ApplicationIntegrationMetadata))]
public partial class ApplicationIntegration
{
}
public class ApplicationIntegrationMetadata
{
[NotToCrud]
public ICollection<Profile> Profiles { get; set; }
}
[AttributeUsage(AttributeTargets.All)]
public class NotToCrud : System.Attribute
{
}
I've created an extension method based that checks if the class has a specific attribute on the property
public static bool CheckIfPropertyIsAnnotated<T>(this object ctx, string propName)
{
var returnValue = false;
if (!string.IsNullOrWhiteSpace(propName))
{
var thisType = ctx.GetType();
var metadataTypes = thisType.GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray();
var metadata = metadataTypes.FirstOrDefault();
if (metadata != null)
{
var properties = metadata.MetadataClassType.GetProperties();
var found = properties.FirstOrDefault(d => d.Name == propName);
if (found != null)
{
returnValue = Attribute.IsDefined(found, typeof(T));
}
}
}
return returnValue;
}
I've created two separate unit tests to find my issue.
This one works.
[TestCase("Profiles", Result = true, TestName = "Valid property")]
public bool HasAttribute(string propName)
{
var test = new ApplicationIntegration();
var actual = test.CheckIfPropertyIsAnnotated<NotToCrud>(propName);
return actual;
}
This one returns false
[Test]
public void HasAttributeWithAssembly()
{
var myTypes = System.Reflection.Assembly.GetAssembly(typeof(ApplicationIntegration)).GetTypes().Where(d => d.Name == "ApplicationIntegration") .ToList();
foreach (var item in myTypes)
{
var actual = item.CheckIfPropertyIsAnnotated<NotToCrud>("Profiles");
Console.WriteLine($"{item.Name} - {actual.ToString()}");
Assert.AreEqual(true, actual);
}
}
the problem seems to be with (var thisType = ctx.GetType())
On the second test, it returns
object.GetType returned
{Name = "RuntimeType" FullName = "System.RuntimeType"} System.RuntimeType
instead of
{Name = "ApplicationIntegration" FullName = "Apm.Model.ApplicationIntegration"}
Any clue how to get around this?
Because item is a Type (with value typeof(ApplicationIntegration)), not an ApplicationIntegration. You can create an object with Activator.CreateInstance. Like:
var myTypes = System.Reflection.Assembly.GetAssembly(typeof(ApplicationIntegration)).GetTypes().Where(d => d.Name == "ApplicationIntegration") .ToList();
foreach (Type type in myTypes)
{
object obj = Activator.CreateInstance(type);
var actual = obj.CheckIfPropertyIsAnnotated<NotToCrud>("Profiles");

Copying All Class Fields and Properties To Another Class

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);
}

Get property of generic class

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);
}
}

How can I avoid using a string member name to get a member of an anonymous type?

I'm using the following code to retrieve named members from an anonymous type. Is there some way I could convert the follwing code to use a lambda expression to achieve this, or at least to allow the calling code to use a lamda, even if 'deep down' I have to use a string?
private T GetAnonymousTypeMember<T>(object anonymousType, string memberName) where T: class
{
var anonTypesType = anonymousType.GetType();
var propInfo = anonTypesType.GetProperty(memberName);
return propInfo.GetValue(anonymousType, null) as T;
}
ADDED:
This is how anonymousType arrives. The GetAnonymousTypeMember method is private to a class whose only public method is declared as follows:
public void PublishNotification(NotificationTriggers trigger, object templateParameters)
I call this method:
PublishNotification(NotificationTriggers.RequestCreated, new {NewJobCard = model});
That new {NewJobCard = model} is what is passed to GetAnonymousTypeMember as anonymousType.
public U GetMemberValue<T, U>(T instance, Expression<Func<T, U>> selector)
{
Type type = typeof(T);
var expr = selector.Body as MemberExpression;
string name = expr.Member.Name;
var prop = type.GetProperty(name);
return (U)prop.GetValue(instance, null);
}
Will enable to to do:
string name = GetMemberValue(new { Name = "Hello" }, o => o.Name);
But why don't You just use dynamic? eg:
class MyClass
{
public int member = 123;
}
class Program
{
static void Main(string[] args)
{
MyClass obj = new MyClass();
dynamic dynObj = obj;
Console.WriteLine(dynObj.member);
Console.ReadKey();
}
}
You could also involve ExpandoObject
List<dynamic> objs = new List<dynamic>();
dynamic objA = new ExpandoObject();
objA.member = "marian";
objs.Add(objA);
dynamic objB = new ExpandoObject();
objB.member = 123;
objs.Add(objB);
dynamic objC = new ExpandoObject();
objC.member = Guid.NewGuid();
objs.Add(objC);
foreach (dynamic obj in objs)
Console.WriteLine(obj.member);
Console.ReadKey();
You mean something like this?
private R GetAnonymousTypeMember<T, R>(T anonymousType, Expression<Func<T, R>> e) where T : class
{
return e.Compile()(anonymousType);
}
public void Do()
{
var x = new {S = "1", V = 2};
var v = GetAnonymousTypeMember(x, _ => _.V);
}
No, when you send the object as the type object, there is no specific type information for the parameter. If you want to access the members of the object you need to use reflection to get the type information from the object itself.
Using a lambda expression to get the member would work, but that would be utterly pointless...

Categories