尽管我看了多个SO帖子和其他任何我能想到的东西,但我在这里完全迷失了。
我的目标是创建一个非常简单的映射器。它只需将一个对象的高级原始值和字符串值映射到另一个对象中,就可以作为一些单元测试工具使用。它不需要复杂或其他什么 - 只需遵循以下基本算法:
- 从
TFrom
获取所有属性 - 从
TTo
获取所有属性 - 获取两者都匹配的所有属性名称
- 我知道这可能是一个错误,因为它们可能具有相同的名称但不同的类型,但让我们将其搁置。这不是我在此遇到的问题 - 类之间的属性和类型匹配。
- 创建一个
TTo
的实例,我们可以将其复制到。 - 对于在对象之间映射的每个属性:
- 从
from
对象中获取值 - 将该值转换为属性的类型
- 在
to
对象上设置该值
- 从
问题在于,无论我做什么以及属性的类型是什么(例如int
或string
),我都会得到以下错误:
对象与目标类型不匹配。
这是我正在使用的代码:
public TTo Map<TFrom, TTo>(TFrom from)
{
if (from == null) return default;
var fromProps = GetProperties(typeof(TFrom));
var toProps = GetProperties(typeof(TTo));
// Props that can be mapped from one to the other
var propsToCopy = fromProps.Intersect(toProps, new PropertyComparer()).ToList();
var returnObject = (TTo)Activator.CreateInstance(typeof(TTo));
foreach (var prop in propsToCopy)
{
// Copy the values
var fromValue = prop.GetValue(from, null);
var convertedValue = Convert.ChangeType(fromValue, prop.PropertyType);
prop.SetValue(returnObject, convertedValue, null);
}
return returnObject;
}
public PropertyInfo[] GetProperties(Type objectType)
{
var allProps = objectType.GetProperties(
BindingFlags.Public | BindingFlags.Instance);
return allProps.Where(p => p.PropertyType.IsPrimitive ||
p.PropertyType == typeof(string)).ToArray();
}
private class PropertyComparer : IEqualityComparer<PropertyInfo>
{
public bool Equals(PropertyInfo x, PropertyInfo y)
{
return x.Name.Equals(y.Name);
}
public int GetHashCode(PropertyInfo obj)
{
return obj.Name.GetHashCode();
}
}
以下是一个示例,展示我如何调用它以及样本类:
public class Foo
{
public string StringProp { get; set; }
public int IntProp { get; set; }
}
public class FooOther
{
public string StringProp { get; set; }
public int IntProp { get; set; }
}
var foo = new Foo { IntProp = 1, StringProp = "foo" };
var mappedFoo = Map<Foo, FooOther>(foo);
关于Visual Studio,我唯一从观察窗口获得的提示是:如果属性类型是string
,观察窗口会将convertedValue
的类型报告为object
。如果属性类型是int
,观察窗口则会报告object {int}
。
PropertyInfo
实际上与对象有任何有意义的连接。我只是把它看作是关于属性的一个脱离实际对象的事实表,只要对象之间的名称和类型相同,为什么它们在技术上是两个不同的类就无所谓呢?但显然你不能把它们分开。知道这点很好! - Ari Roth