除了 System.Type 之外,无需任何其他信息即可转换对象
对于 SO 问题,我最近编写了一个通用扩展方法,该方法应该加载从另一个对象,即将源的所有属性分配给目标,如果该属性是引用类型,则递归地执行此操作。我使用反射已经取得了很大的进展,但是当涉及到引用类型的属性类型时,我遇到了问题,这是我的第一种方法:
第一种方法:
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
,并且我无法再获取该对象实际具有的属性。
我设想了一种解决方法,要求您显式传递类型,这是相当多余的,因为从理论上讲,应该可以在没有以下情况的情况下进行管理:
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
也可以轻松返回一个该死的对象
,而且我似乎无法以其他方式将对象转换为它本来的样子。当然,我已经在网上寻找过这个问题的答案,但到目前为止我还没有成功。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我还没有查看完整的代码或考虑实现这种方案的全部后果(编辑:如果存在循环引用会发生什么?),但我可以为您提供两个针对您的特定问题的简短修复> 问题:
选项 1:回避问题
使用提供的“正常”参数的运行时类型,而不是类型参数。
将:替换
为:
这当然会在代码中引入一个微小语义更改,因为它可以防止人们想要传递
长颈鹿
但只想要的情况Animal
属性已复制。如果source
和target
具有不同的运行时类型(具有不同的属性),它也会崩溃,但是您可以解决这个问题,而不需要太多麻烦(例如找到最深的公共基类型并使用其属性来代替)。选项 2:更多反射/动态
当然,另一个解决方案是使用
MakeGenericMethod
允许“动态”提供类型参数。这保留了代码的原始语义(未经测试):顺便说一句,没有理由不能使用
dynamic
来完成非常相似的事情。我怀疑您正在尝试将调用“作为”扩展方法, 但这行不通。只需尝试正常的“静态方法”语法即可。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:
with:
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 wantAnimal
properties copied over. It will also blow up ifsource
andtarget
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):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.