Я в полном недоумении, несмотря на просмотр нескольких 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}
.