我面临以下问题:
Object
with different datatypes to a corresponding classtype? 这里是一个例子:
namespace Request
{
public class Source
{
[System.Xml.Serialization.XmlElementAttribute("Class1", typeof(Class1))]
[System.Xml.Serialization.XmlElementAttribute("Class2", typeof(Class2))]
[System.Xml.Serialization.XmlElementAttribute("Class3", typeof(Class3))]
public object Item { get; set; }
}
public class Class1 { ... }
public class Class2 { ... }
public class Class3 { ... }
}
namespace Response
{
public class Destination
{
[System.Xml.Serialization.XmlElementAttribute("Class1", typeof(Class1))]
[System.Xml.Serialization.XmlElementAttribute("Class2", typeof(Class2))]
[System.Xml.Serialization.XmlElementAttribute("Class3", typeof(Class3))]
public object Item { get; set; }
}
public class Class1 { ... }
public class Class2 { ... }
public class Class3 { ... }
}
AutoMapper
不会考虑XmlElementAttribute
来映射此类属性。我能够通过反射解决它:
public object Map(object source, Type destinationParentType, string destinationPropertyName)
{
var prop = destinationParentType.GetProperties(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault(p =>
string.Compare(p.Name, destinationPropertyName, StringComparison.Ordinal) == 0);
if (prop == null || prop.CustomAttributes == null) return null;
var attribute = Attribute.GetCustomAttributes(prop, typeof(XmlElementAttribute))
.Cast<XmlElementAttribute>().SingleOrDefault(a =>
string.Compare(a.Type.Name, source.GetType().Name, StringComparison.Ordinal) == 0);
return attribute == null ? null : AutoMapper.Mapper.Map(source, source.GetType(), attribute.Type);
}
通过这样称呼它:
CreateMap<SourceType, DestinationType>()
.ForMember(d => d.Item, o => o.ResolveUsing(s => Map(s.Item, typeof(DestinationType), "Item")));
基本上,我将确定source
的实际类型并在destination
上获得匹配的类型,然后继续进行简单映射。
我现在的问题是我们需要使用DependencyInjection
进行此操作,因此我创建了以下配置文件:
主要:
public class MainProfile : AutoMapper.Profile
{
[Dependency]
internal AttributeMapper AttributeMapper { get; set; } <--This is not resolved
public MainProfile()
{
CreateMap ...
CreateMap<SourceType, DestinationType>()
.ForMember(d => d.Item, o => o.ResolveUsing(s => AttributeMapper.Map(s.Item, typeof(DestinationType), "Item")));
^-- this instance is null
}
}
然后使用XmlElementAttributes
映射属性的映射器:
public class AttributeProfile : AutoMapper.Profile
{
public AttributeProfile()
{
CreateMap<Source.Class1, Destination.Class1>();
CreateMap<Source.Class2, Destination.Class2>();
CreateMap<Source.Class3, Destination.Class3>();
}
}
我这样注册他们:
var mainConfig = new MapperConfiguration(c =>
{
c.AddProfile<MainProfile>();
//Other Profiles
});
var helperConfig = new MapperConfiguration(c =>
{
c.AddProfile<AttributeProfile>();
});
Container.RegisterType<AttributeMapper>();
Container.RegisterInstance(mainConfig.CreateMapper(), new ContainerControlledLifetimeManager());
Container.RegisterInstance("AttributeMapper", helperConfig.CreateMapper(),
new ContainerControlledLifetimeManager());
然后我的AttributeMapper类是这样的:
public class AttributeMapper
{
private readonly IMapper _mapper;
public AttributeMapper([Dependency("AttributeMapper")] IMapper mapper)
{
_mapper = mapper;
}
public object Map(object source, Type destinationParentType, string destinationPropertyName)
{
//Same method from the one above, but I am using _mapper instead of AutoMapper.Mapper.Map
return attribute == null ? null : _mapper.Map(source, source.GetType(), attribute.Type);
}
}
但是我在Object Refence not set to an instance of an object
类的AttributeMapper
属性中得到了MainProfile
。
Dependency
的个人资料是AutoMapper
的问题,这就是为什么我无法进行此工作的原因?还有其他方法可以使用XmlElementAttributes
来修复此AutoMapper
映射吗?
我愿意寻求其他可以帮助您的方式。
答案 0 :(得分:0)
感谢Lucian Bargaoanu分享了他的想法。如果可以的话,我会将您的评论标记为答案。
我创建了一个XmlElementAttributeResolver
(可以使用更通用的名称),如下所示:
public class XmlElementAttributeResolver : IMemberValueResolver<object, object, object, object>
{
public object Resolve(object source, object destination, object sourceMember, object destMember, ResolutionContext context)
{
var sourceMemberType = sourceMember.GetType();
var destinationNamespace = destination.GetType().Namespace;
var destinationMemberType = destination.GetType().Assembly.GetTypes()
.FirstOrDefault(t => t.Name == sourceMemberType.Name && t.Namespace == destinationNamespace);
return destinationMemberType == null
? null
: context.Mapper.Map(sourceMember, sourceMemberType, destinationMemberType);
}
}
在我的MainProfile
中使用解析器可以早先删除对我的AttributeMapper
的依赖关系:
public class MainProfile : AutoMapper.Profile
{
//[Dependency]
//internal AttributeMapper AttributeMapper { get; set; } <--This is not resolved from UnityContainer
public MainProfile()
{
CreateMap ...
CreateMap<SourceType, DestinationType>()
.ForMember(d => d.Item, o => o.ResolveUsing<XmlElementAttributeResolver, object>(s => s.Item));
}
}
并且由于解析器的RuntimeMapper
参数中有ResolutionContext
,因此我不需要将映射器注入解析器。因此,我的mapper容器变得更简单了:
var config = new MapperConfiguration(c =>
{
c.AddProfile<MainProfile>();
//Other Profiles
});
Container.RegisterInstance(config.CreateMapper(), new ContainerControlledLifetimeManager());