Cast object without additional information than its System.Type

For the question, https://stackoverflow.com/a/312799/16/163899/ ... I recently wrote a universal extension method that should load an object from another, i.e. assign all the properties of the target source and therefore do it recursively if the property is a reference. I used reflection quite far, but I ran into a problem when it comes to property types that are reference types, here is my first approach:

First approach:

public static void Load<T>(this T target, T source, bool deep) { foreach (PropertyInfo property in typeof(T).GetProperties()) { if (property.CanWrite && property.CanRead) { if (!deep || property.PropertyType.IsPrimitive || property.PropertyType == typeof(String)) { property.SetValue(target, property.GetValue(source, null), null); } else { property.GetValue(target, null).Load(property.GetValue(source, null), deep); } } } } 

The problem is that PropertyInfo.GetValue returns an object, subsequently T will be equal to object in the recursive call, and I can no longer get the properties that the object actually has.

I came up with a workaround that requires you to explicitly specify a type that is pretty redundant, since theoretically you can do without it:

  public static void Load<T>(this T target, Type type, T source, bool deep) { foreach (PropertyInfo property in type.GetProperties()) { if (property.CanWrite && property.CanRead) { if (!deep || property.PropertyType.IsPrimitive || property.PropertyType == typeof(String)) { property.SetValue(target, property.GetValue(source, null), null); } else { object targetPropertyReference = property.GetValue(target, null); targetPropertyReference.Load(targetPropertyReference.GetType(), property.GetValue(source, null), deep); } } } } 

I also tried using dynamic targetPropertyReference , but then I get an exception at runtime that the Load method cannot be found, it infuriates.

In addition, Convert.ChangeType also returns a damn object too, and I cannot otherwise render the object as it is. Of course, I searched for the answer to this on the net, but so far I have not been successful.

+3
source share
1 answer

I did not look at the full code or consider the full consequences of implementing such a scheme (EDIT: what happens if there are circular links?), But I can give you two short fixes for your specific problem:

Option 1: Avoid the Problem

Use the runtime type of the supplied "normal" argument, not the type argument.

Replace:

 typeof(T).GetProperties() 

with:

 // You need null-checks around this: // you can't realistically continue if target is null anyway. target.GetType().GetProperties() 

This, of course, introduces a slight semantic change in your code, as it prevents scripts when you need to pass Giraffe objects, but just want the Animal properties to be copied. It will also explode if source and target have different runtime types (having different properties), but you can get around this without any special problems (for example, find the deepest common base type and use its properties instead).


Option 2: More Reflection / Dynamic

Another solution, of course, is to use MakeGenericMethod , which allows you to dynamically specify a type argument. This supports the original semantics of the code (untested):

 typeof(MyClass).GetMethod("Load") .MakeGenericMethod(property.PropertyType) .Invoke(null, property.GetValue(target, null), property.GetValue(source, null), deep); 

Btw, there is no reason why you cannot use dynamic to achieve something very similar. I suspect that you are trying to make an "how" extension method but this will not work . Just try the regular "static-method" syntax.

+2
source

Source: https://habr.com/ru/post/1338801/


All Articles