没有任何信息而不是System.Type的Cast对象

时间:2011-02-08 19:52:55

标签: c# generics reflection types extension-methods

对于SO question我最近编写了一个通用扩展方法,该方法应该从另一个加载一个对象,即将源的所有属性分配给目标,如果属性是引用类型,则递归地执行此操作。我使用反射得到了很多,但是当涉及到引用类型的属性类型时遇到了问题,这是我的第一个方法:

第一种方法:

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

这里的问题是PropertyInfo.GetValue返回一个对象,随后T将在递归调用中等于object,我再也无法获得该对象实际拥有的属性。

我设想了一种解决方法,它要求你明确地传递Type,这是非常多余的,因为理论上应该可以在没有的情况下进行管理:

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

我也尝试使用dynamic targetPropertyReference,但后来我得到了一个运行时异常,即无法找到Load方法,这是令人愤怒的。

除了Convert.ChangeType之外,还会轻易地返回一个血腥的object,而我似乎无法将该对象强制转换为它。当然,我已经在网上找到了答案,但到目前为止我还没有成功。

1 个答案:

答案 0 :(得分:2)

我没有查看完整代码或考虑实现此类方案的全部后果(编辑:如果存在循环引用会发生什么?),但我可以为您的具体提供两个简短修复问题:

选项1:避开问题

使用提供的“normal”参数的运行时类型,而不是 type-argument

替换:

typeof(T).GetProperties()

with:

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

这当然会在您的代码中引入次要语义更改,因为它可以防止人们希望传递Giraffe但只需要复制Animal属性的情况过度。如果sourcetarget具有不同的运行时类型(具有不同的属性),它也会爆炸,但是你可以毫不费力地解决这个问题(例如找到最深的共同基类型和改为使用属性。)


选项2:更多反思/动态

另一种解决方案当然是使用MakeGenericMethod来允许“动态”提供type-argument。这维护了代码的原始语义(未经测试):

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

顺便说一句,没有的原因是你无法使用dynamic来完成非常相似的事情。我怀疑你正试图将“呼叫”称为扩展方法,but that won't work。只需尝试正常的“静态方法”语法。