Closed jorisdebock closed 4 years ago
Maybe I should always wrap those invalid mapping in MapAToB
method invocation and those missing methods should be provided as partial methods?
That might even be better yes, then its not only for "on build", like so?
generated code
public partial class GreeterServiceMapper
{
public HelloReply MapReplyHello(Hello hello)
{
return new HelloReply()
{
DateTime = MapDateTime(hello.DateTime),
TimeSpan = MapTimeSpan(hello.TimeSpan)
};
}
public HelloReply MapReplyHello2(Hello hello)
{
return new HelloReply()
{
DateTime = MapDateTime(hello.DateTime),
TimeSpan = MapTimeSpan(hello.TimeSpan)
};
}
public partial Timestamp MapDateTime(DateTime dateTime);
public partial Duration MapTimeSpan(TimeSpan timeSpan);
}
implemented partial methods
public partial class GreeterServiceMapper
{
public partial Timestamp MapDateTime(DateTime dateTime) => dateTime.ToTimestamp();
public partial Duration MapTimeSpan(TimeSpan timeSpan) => timeSpan.ToDuration();
}
in case there are multiple invalid of the same source to target types it should only generate one partial method.
I need to verify if this is easy to implement and I will let know.
UPDATE: Those extra methods cannot be marked as partial because the partial method has to return void - partial method is more like "optional" method. Anyway, the basic concept should work.
One thing that might not work with the partial class solution is the following
for timespan it actually currently generates the following mapping, which does compile but is actually incorrect behavior.
TimeSpan = new Google.Protobuf.WellKnownTypes.Duration()
{
Seconds = hello.TimeSpan.Seconds
},
Providing custom mapping upfront, which should be the preferred mapping to use does solve this or some other way to tell the mapping generator that this should be a partial method.
What do you think about this example?
I can try to combine both ideas by providing configuration options:
namespace MappingGenerator.OnBuildGenerator
{
[AttributeUsage(AttributeTargets.Interface)]
[Conditional("CodeGeneration")]
public class MappingInterface : Attribute
{
public MappingInterface(params System.Type[] typeMappers)
{
TypeMappers = typeMappers;
}
public System.Type[] TypeMappers { get; }
public bool UsePartialClassMethodsForMissingMappings {get; set;}
}
}
Not sure what's the right name for this flag but I hope you get the gist.
@wazowsk1 good news, I've just implemented your idea for VS plugin - check my last commit referenced for this issue. I think adding this feature for OnBuildGenerator should be now quite easy.
I've just released MappingGenerator.OnBuildGenerator.1.15.380 with the requested feature. I've used the named parameter instead of the custom constructor to make the MappingInterfaceAttribute open for further extensions. A sample usage:
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using MappingGenerator.OnBuildGenerator;
namespace MappingGenerator.Test.MappingGenerator.TestCaseData
{
[MappingInterface(CustomStaticMappers = new []{typeof(CustomMappers)})]
public interface ISampleMapper
{
UserDTO Map(UserEntity entity);
}
public class CustomMappers
{
public static AddressDTO MapAddress(AddressEntity addressEntity)
{
return new AddressDTO()
{
City = addressEntity.City,
ZipCode = addressEntity.ZipCode,
Street = addressEntity.Street,
FlatNo = addressEntity.FlatNo,
BuildingNo = addressEntity.BuildingNo
};
}
}
Please update MappingGenerator.OnBuildGenerator
and let me know if everything works as you expected.
I have tested it with my test project and bigger project and it is working as expected 👍
without providing a custom mapper
DateTime = hello.DateTime,
TimeSpan = new Duration()
{
Seconds = hello.TimeSpan.Seconds
}
with providing a custom mapper
DateTime = GrpcService1.CustomMappers.ProtoTimeMapper.MapDateTime(hello.DateTime),
TimeSpan = GrpcService1.CustomMappers.ProtoTimeMapper.MapTimeSpan(hello.TimeSpan)
Thanks for testing
In some cases the generated mapping code is not valid due different types.
for example, these two types
will create the following (invalid) mapping
Can we extend the MappingInterface like so?
providing a custom type mapper
using like so
and the expected results be like
given that: