问题
Consider the following scenario. I have a number of classes that share a common base class and I have defined an automapper mapping for each derived class. Something like this:
class A : Base {}
class B : Base {}
class ContractA : ContractBase {}
class ContractB : ContractBase {}
void Foo()
{
Mapper.CreateMap<A, ContractA>();
Mapper.CreateMap<B, ContractB>();
}
So far so good. But now I want to create a method like this:
ContractBase Foo()
{
Base obj = GetObject();
return Mapper.???
}
The problem is that all of AutoMapper's Map variants require that I either know the destination type at compile time or have an object of that type available at runtime. This is seriously frustrating since I have defined only one map for each source type. AutoMapper should be able to infer the destination type given only the source type.
Is there any good way around this? I want to avoid creating a dictionary mapping source types to destination types. While this would work, it would mean that I'd essentially have to define two mappings for every source type.
回答1:
You could access the mappings stored in AutoMapper:
ContractBase Foo() {
Base obj = GetObject();
var sourceType = obj.GetType();
var destinationType = Mapper.GetAllTypeMaps().
Where(map => map.SourceType == sourceType).
// Note: it's assumed that you only have one mapping for the source type!
Single().
DestinationType;
return (ContractBase)Mapper.Map(obj, sourceType, destinationType);
}
回答2:
You can turn it around and ask Base
to give you a mapped contract:
ContractBase Foo() {
Base obj = GetObject();
return obj.ToContract();
}
With this code:
abstract class Base {
public abstract ContractBase ToContract();
}
class A : Base {
public override ContractBase ToContract() {
return Mapper.Map<A, ContractA>(this);
}
}
class B : Base {
public override ContractBase ToContract() {
return Mapper.Map<B, ContractB>(this);
}
}
UPDATE: if you must separate the logic from the classes, you could use a visitor:
ContractBase Foo() {
Base obj = GetObject();
var visitor = new MapToContractVisitor();
obj.Accept(visitor);
return visitor.Contract;
}
This is what it looks like:
abstract class Base {
public abstract void Accept(IBaseVisitor visitor);
}
class A : Base {
public override void Accept(IBaseVisitor visitor) {
visitor.Visit(this);
}
}
class B : Base {
public override void Accept(IBaseVisitor visitor) {
visitor.Visit(this);
}
}
interface IBaseVisitor {
void Visit(A a);
void Visit(B b);
}
class MapToContractVisitor : IBaseVisitor {
public ContractBase Contract { get; private set; }
public void Visit(A a) {
Contract = Mapper.Map<A, ContractA>(a);
}
public void Visit(B b) {
Contract = Mapper.Map<B, ContractB>(b);
}
}
Now, all the mapper logic is in the MapToContractVisitor
class, not in the Base
hierarchy classes.
回答3:
I think Mapper.DynamicMap()
and its various overloads are what you're looking for.
来源:https://stackoverflow.com/questions/3866425/how-can-i-use-automapper-to-map-an-object-to-an-unknown-destination-type