Pergunta

ATUALIZAR: Esse material evoluiu para um bom projeto, veja -o em http://valueinjecter.codeplex.com


Confira isso, acabei de escrever um AutomApper simples, é preciso o valor da propriedade com o mesmo nome e tipo de um objeto e o coloca em outro, e você pode adicionar exceções (ifs, Switch) para cada tipo que você pode precisar

Então me diga o que você acha disso?

Eu fiz isso para que eu pudesse fazer algo assim:

Product –> ProductDTO

ProductDTO –> Product

Foi assim que começou:

Eu uso o tipo de "objeto" em minhas entradas/dto/viewmodels para suspensos porque envio ao html um ienumerableu003CSelectListItem> E eu recebo uma matriz de string de chaves selecionadas de volta

 public void Map(object a, object b)
    {
        var pp = a.GetType().GetProperties();
        foreach (var pa in pp)
        {
            var value = pa.GetValue(a, null);

            // property with the same name in b
            var pb = b.GetType().GetProperty(pa.Name);
            if (pb == null)
            {
                //no such property in b
                continue;
            }

            if (pa.PropertyType == pb.PropertyType)
            {
                pb.SetValue(b, value, null);
            }

        }
    }

ATUALIZAR:O verdadeiro uso:
os métodos de construção (input = dto):

        public static TI BuildInput<TI, T>(this T entity) where TI: class, new()
        {
            var input = new TI();
            input = Map(entity, input) as TI;
            return input;
        }

        public static T BuildEntity<T, TI, TR>(this TI input)
            where T : class, new()
            where TR : IBaseAdvanceService<T>
        {               
            var id = (long)input.GetType().GetProperty("Id").GetValue(input, null);
            var entity = LocatorConfigurator.Resolve<TR>().Get(id) ?? new T();
            entity = Map(input, entity) as T;
            return entity;
        }

        public static TI RebuildInput<T, TI, TR>(this TI input)
            where T: class, new()
            where TR : IBaseAdvanceService<T>
            where TI : class, new()
        {

                return input.BuildEntity<T, TI, TR>().BuildInput<TI, T>();
            }

no controlador:

    public ActionResult Create()
    { 
        return View(new Organisation().BuildInput<OrganisationInput, Organisation>());
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(OrganisationInput o)
    {
        if (!ModelState.IsValid)
        {
            return View(o.RebuildInput<Organisation,OrganisationInput, IOrganisationService>());                
        }
        organisationService.SaveOrUpdate(o.BuildEntity<Organisation, OrganisationInput, IOrganisationService>());
        return RedirectToAction("Index");
    }

O método de mapa real

public static object Map(object a, object b)
        {
            var lookups = GetLookups();

            var propertyInfos = a.GetType().GetProperties();
            foreach (var pa in propertyInfos)
            {
                var value = pa.GetValue(a, null);

                // property with the same name in b
                var pb = b.GetType().GetProperty(pa.Name);
                if (pb == null)
                {
                    continue;
                }

                if (pa.PropertyType == pb.PropertyType)
                {
                    pb.SetValue(b, value, null);
                }
                else if (lookups.Contains(pa.Name) && pa.PropertyType == typeof(LookupItem))
                {
                    pb.SetValue(b, (pa.GetValue(a, null) as LookupItem).GetSelectList(pa.Name), null);
                }
                else if (lookups.Contains(pa.Name) && pa.PropertyType == typeof(object))
                {
                    pb.SetValue(b, pa.GetValue(a, null).ReadSelectItemValue(), null);
                }
                else if (pa.PropertyType == typeof(long) && pb.PropertyType == typeof(Organisation))
                {
                    pb.SetValue(b, pa.GetValue<long>(a).ReadOrganisationId(), null);
                }
                else if (pa.PropertyType == typeof(Organisation) && pb.PropertyType == typeof(long))
                {
                    pb.SetValue(b, pa.GetValue<Organisation>(a).Id, null);
                }
            }

            return b;
        }
Foi útil?

Solução

Uma coisa que você pode querer adicionar é armazenar em cache os bits de reflexão. Se você mapear um objeto duas vezes, provavelmente não deseja procurar todas as coisas de reflexão novamente. Além disso, coisas como GetValue e SetValue são bastante lentas, mudei para os delegados do final do final do limite + reflexão. Femit para acelerar as coisas.

Outras dicas

Apenas use Automapper. Isso é bom, mas crescerá em um mini projeto.

Apenas algumas coisas AM (a verdadeira) é:

  • relatar se você tem propriedades que não podem ser mapeadas para
  • Objetos achatados
  • Fornecendo ganchos para você personalizar alguns aspectos, não em uma grande instrução Switch
  • Usando expressão.compile por motivos de perf, em vez de reflexão diretamente

Mas é certamente um espaço interessante para mexer, e a idéia de mapeamento automático é certamente útil.

Um pouco como di em 15 ou 33 Linhas vs ninje ou seus amigos - legal, mas por quê?

Eu pego que você leu o Artigo e comentários sobre o mapeamento de 2 vias no blog de Jimmy ?

Apenas um pensamento:

Pode -se perguntar qual é o sentido de uma abstração se a abstração é tão facilmente mapeada para que seja abstrata.

Você pode adicionar exceções (ifs, switch) para cada tipo que você pode precisar

Você não vai fazer isso. Seriamente. As declarações de casos que atuam nos tipos de objetos são ruins no estilo OOP. Quero dizer, muito ruim. Como dirigir com uma bebida de vodka dentro do seu estômago. Pode funcionar por algum tempo, mas, eventualmente, você tem problemas.

Ok, Jimmy lhe disse para não usar o AutomApper ... mas aposto que ele quis dizer outra coisa. Agora, você inventou algo diferente - algo que deixa Jimmy feliz? ;-) Não, você acabou de fazer seu próprio AutomApper semi-rolado. E Jimmy disse para você não usá -lo! ;-)

Então, aqui está minha sugestão: ignore o que Jimmy diz, apenas pense em si mesmo .. e use o Automapper ;-)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top