2010-10-05 13 views
6

Rozważmy następujący scenariusz. Mam kilka klas, które mają wspólną klasę podstawową i zdefiniowałem mapowanie automatów dla każdej klasy pochodnej. Coś takiego:Jak używać Automappera do odwzorowania obiektu na nieznany typ miejsca docelowego?

class A : Base {} 

class B : Base {} 

class ContractA : ContractBase {} 

class ContractB : ContractBase {} 

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

Jak dotąd tak dobrze. Ale teraz chcę utworzyć metodę tak:

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

    return Mapper.??? 
} 

Problem polega na tym, że wszystkie Mapa wariantów AutoMapper wymagają że albo znać typ docelowy w czasie kompilacji lub mieć obiekt tego typu dostępnych na starcie. Jest to bardzo frustrujące, ponieważ zdefiniowałem tylko jedną mapę dla każdego typu źródła. AutoMapper powinien mieć możliwość określenia typu celu, biorąc pod uwagę tylko typ źródła.

Czy jest jakiś dobry sposób obejścia tego? Chcę uniknąć tworzenia słownika mapującego typy źródłowe na typy docelowe. Chociaż to zadziałałoby, oznaczałoby to, że zasadniczo musiałbym zdefiniować dwa mapowania dla każdego typu źródła.

+1

użycie valueinjecter.codeplex.com – Omu

Odpowiedz

10

Można uzyskać dostęp do mapowania przechowywanych w 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

To rozwiązanie nie działa w wersji 5, ponieważ nie mamy już 'Mapper.GetAllTypeMaps()' już –

+0

@MohammadDayyan: dzięki za informację. Być może [ten problem] (https://github.com/AutoMapper/AutoMapper/issues/1252) pomoże. –

1

Myślę, że Mapper.DynamicMap() i jego różne przeciążenia są tym, czego szukasz.

+0

Wydaje się te metody po prostu map jednego obiektu na inny (zamiast wrócić nowy obiekt). Nadal wymagają typu miejsca docelowego. –

3

Można włączyć go dookoła i poprosić Base aby dać odwzorowaną zamówienia:

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

z tym kodem:

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: jeśli trzeba oddzielić logikę z klas , możesz użyć gościa:

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

To jak to wygląda:

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

Teraz cała logika odwzorowujący jest w klasie MapToContractVisitor, a nie w Base klas hierarchii.

+0

To sprytnie, ale niestety to nie działa dla nas. Klasy te reprezentują wiadomości do różnych systemów. Nie są wzajemnie świadome siebie nawzajem. –

+0

OK, pozwól mi spróbować jeszcze raz ... –

+0

To naprawdę nie rozwiązuje pierwotnego problemu. Moim problemem nie jest to, że nie widzę sposobu, aby zrobić mapowanie, ale chcę uniknąć powielania wysiłków. Dzięki temu rozwiązaniu muszę zrobić dwie rzeczy za każdym razem, gdy dodaję nową parę klas. Najpierw muszę zdefiniować mapowanie automapperów, a następnie utworzyć metodę odwiedzającą. Mam nadzieję, że uda mi się zdefiniować mapowanie i nic więcej. –

Powiązane problemy