2010-10-05 23 views
6

Tenga en cuenta la situación siguiente. Tengo varias clases que comparten una clase base común y he definido una asignación de Automapper para cada clase derivada. Algo como esto:¿Cómo puedo usar Automapper para asignar un objeto a un tipo de destino desconocido?

class A : Base {} 

class B : Base {} 

class ContractA : ContractBase {} 

class ContractB : ContractBase {} 

void Foo() 
{ 
    Mapper.CreateMap<A, ContractA>(); 
    Mapper.CreateMap<B, ContractB>(); 
} 

Hasta ahora todo bien. Pero ahora quiero crear un método como este:

ContractBase Foo() 
{ 
    Base obj = GetObject(); 

    return Mapper.??? 
} 

El problema es que todas las variantes Mapa de AutoMapper requieren que sea saber el tipo de destino en tiempo de compilación o tener un objeto de ese tipo en tiempo de ejecución. Esto es muy frustrante ya que he definido solo un mapa para cada tipo de fuente. AutoMapper debería poder inferir el tipo de destino dado solo el tipo de fuente.

¿Hay alguna forma de evitar esto? Quiero evitar crear un tipo de fuente de mapeo de diccionario para los tipos de destino. Si bien esto funcionaría, significaría que esencialmente tendría que definir dos asignaciones para cada tipo de fuente.

+1

uso valueinjecter.codeplex.com – Omu

Respuesta

10

Se puede acceder a las asignaciones almacenados en 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); 
} 
+0

Esta solución no funciona en la versión 5, porque no tenemos 'Mapper.GetAllTypeMaps()' más –

+0

@MohammadDayyan: gracias por la información. Quizás [este problema] (https://github.com/AutoMapper/AutoMapper/issues/1252) ayude. –

1

Creo que Mapper.DynamicMap() y sus varias sobrecargas son lo que estás buscando.

+0

parece que estos métodos sólo establecen un objeto a otro (en lugar de devolver un nuevo objeto). Todavía requieren el tipo de destino. –

3

Puede darle la vuelta y pedir Base para darle un contrato asignada:

ContractBase Foo() { 
    Base obj = GetObject(); 
    return obj.ToContract(); 
} 

Con este código:

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); 
    } 
} 

ACTUALIZACIÓN: si debe separar la lógica de las clases , puede utilizar un visitante:

ContractBase Foo() { 
    Base obj = GetObject(); 
    var visitor = new MapToContractVisitor(); 
    obj.Accept(visitor); 
    return visitor.Contract; 
} 

Esto es lo que parece:

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); 
    } 
} 

Ahora, toda la lógica asignador está en la clase MapToContractVisitor, no en los Base clases de jerarquía.

+0

Eso es inteligente, pero desafortunadamente no funciona para nosotros. Las clases en cuestión representan mensajes a diferentes sistemas. No se conocen mutuamente. –

+0

Bien, déjame intentarlo de nuevo ... –

+0

Esto realmente no resuelve el problema original. Mi problema no es que no veo la forma de hacer el mapeo, sino que quiero evitar la duplicación de esfuerzos. Con esta solución, debo hacer dos cosas cada vez que agregue un nuevo par de clases. Primero, debo definir el mapeo de Automapper, luego debo crear un método de visitante. Estoy esperando una manera de definir _just_ el mapeo y nada más. –

Cuestiones relacionadas