Cast object without any more info than its System.Type

亡梦爱人 提交于 2019-12-14 01:28:34

问题


For a SO question i quite recently wrote a generic extension method that should load an object from another, i.e. assign all the properties of the source to the target and do so recursively if the property is a reference-type. I got quite far using reflection but i hit a problem when it came to the types of properties 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 here is that PropertyInfo.GetValue returns an object, subsequently T will equal object in the recursive call and i can no longer get the properties that the object actually has.

I conceived of a workaround which requires you to pass the Type explicitly, which is quite redundant since in theory it should be possible to manage without:

    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 a runtime exception that the Load method cannot be found, it is infuriating.

Other than that Convert.ChangeType handily returns a bloody object too and i cannot seem to otherwise cast the object to what it is. Of course i have looked for an answer to this on the net but i have been unsuccessful so far.


回答1:


I haven't looked at the full code or considered the full consequences of implementing such a scheme (EDIT: what will happen if there are cyclic references?), but I can give you two short fixes for your specific problem:

Option 1: Dodge the issue

Use the run-time type of the provided "normal" argument, rather than 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 minor semantic change in your code, in that it prevents scenarios when one would would want to pass a Giraffe but only want Animal properties copied over. It will also blow up if source and target are of different run-time types (having different properties), but you can work around that without too much trouble (e.g. find the deepest common base-type and use its properties instead).


Option 2: More reflection / dynamic

The other solution of course, is to use MakeGenericMethod to allow the type-argument to be provided "dynamically". This maintains 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's no reason you can't use dynamic to accomplish something very similar. I suspect you're trying to do the call "as" an extension-method, but that won't work. Just try the normal "static-method" syntax.



来源:https://stackoverflow.com/questions/4937650/cast-object-without-any-more-info-than-its-system-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!