2010-10-05 119 views
6

考虑以下情况。我有许多共享公共基类的类,并为每个派生类定义了一个自动映射器映射。像这样的:如何使用Automapper将对象映射到未知的目标类型?

class A : Base {} 

class B : Base {} 

class ContractA : ContractBase {} 

class ContractB : ContractBase {} 

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

到目前为止好。但现在我想创建一个方法是这样的:

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

    return Mapper.??? 
} 

的问题是,所有AutoMapper的地图变种的要求,我无论是在编译时知道目标类型或具有该类型在运行时可用的对象。这是非常令人沮丧的,因为我只为每个源类型定义了一个映射。 AutoMapper应该能够推断仅给定源类型的目标类型。

有没有什么好办法解决这个问题?我想避免创建一个字典映射源类型到目标类型。虽然这会起作用,但这意味着我基本上必须为每个源类型定义两个映射。

+1

使用valueinjecter.codeplex.com – Omu 2010-10-05 20:21:09

回答

10

你可以访问存储在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

由于我们没有'Mapper.GetAllTypeMaps()',所以此解决方案在版本5中不起作用 – 2016-07-09 09:58:00

+0

@MohammadDayyan:感谢您的信息。也许[这个问题](https://github.com/AutoMapper/AutoMapper/issues/1252)将有所帮助。 – 2016-07-09 12:27:06

1

我认为Mapper.DynamicMap()和它的各种过载是你在找什么。

+0

看来这些方法只是一个对象映射到另一个(而不是返回一个新的对象)。他们仍然需要目标类型。 – 2010-10-05 18:53:58

3

你可以把它周围,并要求Base给你映射的合同:

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

有了这个代码:

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:如果你必须单独从班级逻辑,你可以使用一个访客:

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

这是什么样子:

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

现在,所有的映射逻辑是在MapToContractVisitor类,而不是在Base层次结构类。

+0

这很聪明,但不幸的是它不适合我们。有问题的类将消息表示给不同的系统。他们并不相互了解对方。 – 2010-10-05 20:36:30

+0

好吧,让我再试一次.... – 2010-10-05 20:45:00

+0

这并不能真正解决原来的问题。我的问题不是我看不到映射的方法,而是我想避免重复的工作。有了这个解决方案,我每次添加一对新类时都必须做两件事。首先,我必须定义自动映射器映射,然后我必须创建一个访问者方法。我希望有一种方法来定义_just_映射,而不是别的。 – 2010-10-06 15:36:38

相关问题