В настоящее время я работаю над сценарием, в котором мне понадобится Automapper, чтобы использовать IO C для создания новых экземпляров. Кроме того, мне нужно было бы зарегистрировать сопоставление для Automapper только при повышении требования (поэтому я не использую файлы профилей). Чтобы добиться того же, я сделал следующее.
var cfg = new MapperConfigurationExpression();
cfg.ConstructServicesUsing(type =>
{
return CreateInstanceUsingIOC(type);
});
cfg.CreateMap<Model1, Model2>()
.ConstructUsingServiceLocator();
var config = new MapperConfiguration(cfg);
var mapper = config.CreateMapper();
var model1UsingIoC = CreateModel1UsingIoC();
model1UsingIoC.MyProfile = new Person();
model1UsingIoC.MyProfile.FirstName = "New First Name";
model1UsingIoC.MyProfile.LastName = "New Last Name";
model1UsingIoC.CommonProperty = "This wont be copied";
var model2b = mapper.Map<Model2>(model1UsingIoC);
Это работает как нужно, однако проблема заключается во внутреннем свойстве Model1.MyProfile. Экземпляр MyProfile в Source и Destination выглядит одинаково.
ReferenceEquals(model2b.MyProfile,model1UsingIoC.MyProfile) // True
Кроме того, я хотел бы создать каждое из пользовательских вложенных свойств, используя Io C. Для этой цели я добавил измененный оператор ConstructServicesUsing как
cfg.ConstructServicesUsing(type =>
{
var instance = CreateInstance(type);
return ReassignProperties(instance);
});
Где ReassignProperties определяется как
public static object ReassignProperties(object obj)
{
if (obj == null) return null;
Type objType = obj.GetType();
PropertyInfo[] properties = obj.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
// Check if its a collection
if (property.IsEnumerable())
{
if (property.GetValue(obj, null) is IEnumerable elems)
{
foreach (var item in elems)
{
ReassignProperties(item);
}
}
}
else
{
// If it is User Defined Type, Recursively loop again
if (property.PropertyType.Assembly == objType.Assembly)
{
var newValue = CreateInstance(property.PropertyType);
property.SetValue(obj, newValue);
var value = property.GetValue(obj);
ReassignProperties(value);
}
else
{
var propValue = property.GetValue(obj, null);
Console.WriteLine($"{property.Name} = {propValue}");
}
}
}
return obj;
}
Но, как можно предположить, это не помогло ни во время отображения, один и тот же экземпляр копируется для подпредприятий. Может ли кто-нибудь подсказать мне, как обеспечить создание нового экземпляра для пользовательских под-свойств при использовании Automapper (ie, новый экземпляр создается и значения копируются, если тип не является примитивным типом)?
Обновление 001
В соответствии с предложением Lucian, я попытался создать собственный маппер следующим образом и добавить его в Mapping Registery.
public class NewInstanceMapper : IObjectMapper
{
public bool IsMatch(TypePair context) => true;
public static object CreateInstance(Type type)
{
try
{
var methodInfo = typeof(IoC).GetMethod(nameof(IoC.Get), BindingFlags.Public | BindingFlags.Static);
var genericMethodInfo = methodInfo.MakeGenericMethod(type);
return genericMethodInfo.Invoke(null, new object[] { null });
}
catch (Exception)
{
return Activator.CreateInstance(type);
}
}
public Expression MapExpression(IConfigurationProvider configurationProvider, ProfileMap profileMap, PropertyMap propertyMap, Expression sourceExpression, Expression destExpression, Expression contextExpression)
{
return Expression.Call(this.GetType(), nameof(CreateInstance), null, Expression.Constant(destExpression.Type));
}
}
И добавил его в MappingRegistery, используя
var cfg = new MapperConfigurationExpression();
cfg.Mappers.Insert(0,new NewInstanceMapper());
Но, как можно догадаться, это создало новый экземпляр, но не скопировало значение
Дополнительные примечания Обратите внимание, что я хотел бы достичь, будет
a) Каждое значение свойства копируется в место назначения в соответствии с соглашениями об именах
b) Каждое свойство назначения (исключение для строки) является новым каждый экземпляр, созданный с использованием Io C, и не совпадающий с экземплярами свойства источника
- c) Точка b содержит вложенные свойства, коллекции (каждый элемент нуждается в коллекции создается с использованием io c и скопированных значений значений вспомогательных свойств)