Generic Dto Mapper
possibly oddball question, but I'm trying to make Dto mappers, and I came across List<T> and Array<T> items in my Dto's that I needed to map by using a foreach loop for each of these items. But I was wondering if there is a way to create a generic mapper of sorts for these things?
I mean I tried starting, but I get stuck..
Currently each of these loops does the same, but with different properties in a different model class.
Here's an example of the foreach loop they do:
however when I try to do this in a static helper class, I get stuck on the following:
49 Replies
Is there specific reason to not use reliable libraries for mapping such as AutoMapper ?
because it's also educational for me 😅
Couldn't you add a condition for this mapper? Something along the lines of
where T : new()
behind the method definition?I've been using the project I'm working on to write a lot of these static generic helper methods to learn about them
Its hard to manage nested collections
Apparently not, because
T
or TS
does not have the new() constraint
I know, which makes it a perfect educational topic 🤣But you can enforce it using the snippet I described, right 🤔
I tried that.. here's what I have:
And why specifically are you trying to add an instance of type
T
while the source is using type TS
?Oh, my bad, it says
TS
.In that case the same
where TS : new()
would apply, wouldn't it? Pretty sure you can also do it for bothokay, so how do I get all the keys now..
What's 'keys' in this context?
Each property?
yea
each of the
TS
properties, as well as the T
properties.
So that I can do
source.Add( new() { TS.PropertyOne = T.PropertyOne } );
sort of..Something along the lines of, keep in mind I haven't validated it;
This is ofc very naive and does not consider if it does not exist on the source type etc etc.
u could pass a delegate for the actual mapping, but then u more or less have the same thing as linq:
which u could use like: (if u want filtering u could add
Func<TFrom, bool>
parameter.)
but u could also just do something like var target = source.Where(element = element >= 2).Select(element => element.ToString());
(this is linq btw)
by using a delegate as parameter u can avoid writing dozens of similar methodsokay, so I used this, but then I must be doing something wrong 😅 help me understand this
You're mapping from source into target, by getting all the properties from source, and telling the target object to use those property names and give the source value of that propertyName to the target propertyName.
but now, when I want to do
SomeListOfComplexItems.ComplexObjectMapper<ComplexItem, ComplexDto>(SomeListOfComplexDtoItems);
I get the following error: Cannot convert from System.Collections.Generic.List<ComplexModel> to System
(and that's where the error message cuts off, but I recon it says System.Collections.Generic.List<ComplexDto>
hard to tell without knowing the real code
Wow... now my mind is melting 🤣
My objects are not as simple as ints and strings though..
I basically have:
so I would then use Linq to do what now?
okay, lemme give you what I have now..
I commented out the foreach, because that's how I did it when I went literal.
I'm doing the same for a much more complex object with four to six of those foreach loops that do basically the same, but with different properties
the
ComplexObjectMapper()
is what was sent earlier:
u would use a
Select()
call there, which is used to transform/map elements. Where()
is to filter elements
Ah, so a Linq way of doing my commented out foreach loops 🤣 that's already much closer to what I wanted
note that
target
is now only a IEnumerable<SomeDto>
, if u would for example would want a List<SomeDto>
, u would do an ToList()
call at the endfair enough. I'm just trying to figure it out though.. eh...
So
List<SomeDto> target = source.Select(element => new SomeDto { SomeProperty: element.SomeProperty } ).ToList()
right?yep
Dude...
you're a hero
and a legend 🤣
actually the linq authors r ;p
though still I'd love to learn how to generic that though... but I'll figure that out eventually
yea they are too.. Linq has saved my ass so many times now
how to generic that thoughbasically without passing a delegate?
Uhhhh reflection is quite slow
I'd suggest using Mapster or AutoMapper
yeah, im not sure what they r meaning, so thats why i was asking
linq isnt that fast either ;p
Faster than reflection though AFAIK
o.O
ofc, reflection is really slow and complex, an alternative would be source generators but thats even more complex.
imo either way it would be adding too much magic to it which can be quite error prone and thus not worth it
Fair enough..
Some LINQ functions are getting a speed boost though in .NET 7
Min and Max for example are getting vectorization finally
well, talking about optimization at this stage isnt really helpful, this might not even be the bottleneck of the program.
write it working -> refactor it clean -> check bottlenecks -> optimize them
Still, using reflection for mapping is not a good idea like this
Just use Mapster :)
The thing is that the senior at my work gave me this "skeleton" format I should follow, and he's making me write my own mappers 😅
Mapster has really good performance
And is easy to use
fair enough
It can also generate mapping code
oh mapster uses code generation
You can do that too
You can also just use the global mapper
Or use the interface it provides
The skeleton I'm using is basically:
Host.MyApp
Host.UnitTests
Domain.PortsAndAdapterInterfaces
Adapter.Persistence
and a Mapper between each of those boundaries
So it has a few options
But you guys have been legends, I'll close the post now as I'm helped!
thanks!!!