我在这里完全失败,尽管我看过多篇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
的类型报告为{{ 1}}。如果属性类型为object
,则观察窗口会报告int
。
答案 0 :(得分:4)
您正在使用的PropertyInfo仍然耦合到它所代表的属性所属的类型,因此您无法使用它来设置另一种类型的对象的值而不会出现错误。
以下是行为的简短示例:
public class A {
public string Id {get;set;}
}
public class B {
public string Id {get;set;}
}
void Main()
{
var test = new A() { Id = "Test"};
var prop = test.GetType().GetProperty("Id");
var b = (B)Activator.CreateInstance(typeof(B));
var fromValue = prop.GetValue(test);
var converted = Convert.ChangeType(fromValue, prop.PropertyType);
prop.SetValue(b, converted, null); // Exception
}
如果您将PropertyInfo视为A的成员,这是有道理的。要解决此问题,您需要获取特定于您的类型的属性信息。我可以用以下内容修复我的例子:
var propTo = typeof(B).GetProperty(prop.Name);
propTo.SetValue(b, converted, null);
Console.WriteLine(b.Id); // Output: Test
将这些内容整合在一起,如果您将foreach的内容更改为以下内容,则应明确说明:
foreach (var prop in propsToCopy)
{
// Copy the values
var fromValue = prop.GetValue(from, null);
var convertedValue = Convert.ChangeType(fromValue, prop.PropertyType);
var propTo = typeof(TTO).GetProperty(prop.Name);
propTo.SetValue(returnObject, convertedValue, null);
}