cezarypiatek / MappingGenerator

:arrows_counterclockwise: "AutoMapper" like, Roslyn based, code fix provider that allows to generate mapping code in design time.
https://marketplace.visualstudio.com/items?itemName=54748ff9-45fc-43c2-8ec5-cf7912bc3b84.mappinggenerator
MIT License
1.03k stars 120 forks source link

Interface mapping #106

Closed biqas closed 4 years ago

biqas commented 4 years ago

Hi,

are also mappings from interface to interface supported, if not would be great if such feature would be available.?

Like: AgileMapper has https://github.com/agileobjects/AgileMapper/issues/163 https://agilemapper.readthedocs.io/Using-Execution-Plans/

cezarypiatek commented 4 years ago

It's not possible to map directly to interface because it's not possible to instantiate an interface. Can you provide a sample of the expected mapping code that should be generated?

biqas commented 4 years ago

Hi,

of course not directly to interfaces.

public class Foo : IFooView1, IFooView2
{
    public Bar Bar { get; set; }

    public string A { get; set; }

    public string B { get; set; }

    IBar IFooView1.Bar => this.Bar;
}

public interface IFooView1
{
    IBar Bar { get; }

    string A { get; set; }
}

public interface IFooView2
{
    string B { get; set; }
}

public class Bar : IBar
{
    public int C { get; set; }
}

public interface IBar
{
    int C { get; set; }
}

Mapping:

IFooView1 fooView1 = new Foo();

IFooView1 mappedFooView1 = Mapper.Map<Foo>(fooView1);

The is just an example not a proposal for the syntax.

cezarypiatek commented 4 years ago

I mean, please provide a sample code that should be generated by MappingGenerator. I'm pretty sure that generating code for generic methods should be supported right now:

public TDestination Map<TDestination>(ISource source) whre TDestination: IDestination
{

}

Can you try and let me know if it works as expected?

biqas commented 4 years ago

If a property which is expecting a interface, then the mapping code is not able to recognize which instance to use, becasue with Map TDestination you can only provide the instance for the root object. Either the generated mapping code should not be inlined or it is calling another generated mapping definitions or it should have possibilities to provide all nested instance types.

public class Foo
    {
        public IBar Bar { get; set; }
    }

    public interface IBar
    {
        int C { get; set; }
    }

Generated code:

public static class Mapper
{
    public static Foo M(Foo foo)
    {
        return new Foo()
        {
            Bar = new IBar()
            {
                C = foo.Bar.C
            }
        };
    }
}

The property "Bar" is generated but with "new IBar()", because the generator has no infos which type to use.

cezarypiatek commented 4 years ago

Ok, now I understand. Unfortunately, it's not supported right now by MappingGenerator to provide some hints related to mapping sub-types (sub-properties. Can't promise when this will be implemented.

biqas commented 4 years ago

Cant' you make use of AgileMapper? It seems he has done a lot of work for all of those configurations, the only thing is it is for runtime. He has a get execution plan which you can theoretically use to generate code.

cezarypiatek commented 4 years ago

AgileMapper and MappingGenerator seem to work completely differently (runtime vs design time) so I'm afraid there's nothing in AgileMapper that I can reuse.

I think I can add an option to MappingGenerator to search a function in the current type that can perform a given conversion (let's say we need a T1->T2 conversion and there is a function with signature T2 XXX(T1 x) ) and invoke that method instead of generating a mapping code. What do you think about such an approach for solving this problem?

biqas commented 4 years ago

Not sure if this would solve all needs, but for simple cases would help.

cezarypiatek commented 4 years ago

Mapping with custom conversion has been implemented as part of #119

This should be available under the following option image

Please let me know if this fits your needs.