Skip to content

MortenChristiansen/TypeBridge

Repository files navigation

Type Bridge

A .NET source generator that allows you to map from one type to another with a similar signature in a strongly typed manner. An early version of the package is available from NuGet here.

Roadmap

This library is very new and as such lacks many essential features and will most likely fail spectacularly if used in anything resembling production. The below list enumerates the features which I have currently identified as reasonable for the library to have.

Version 1.0

  • B b = a.Map(); // Variable assignment
  • a.B = c.Map(); // Property assignment
  • Process(a.Map()); // Method argument
  • new B(a.Map()); // Constructor argument
  • new B<int>(a.Map(), 1); // Mapping to a non-generic constructor argument
  • new B<A>(a.Map()); // Mapping to a generic constructor argument
  • Process<int>(a.Map(), 1); // Mapping to a non-generic type
  • Process<A>(a.Map()); // Mapping to generic type
  • _a = b.Map(); // Member assignment
  • var v = new B { CValue = a.Map() }; // Object initializers
  • Recursively map complex types
  • Map List properties
  • Map IEnumerable properties
  • Map T[] properties
  • Map properties where source type is subtype of destination
  • Map properties where destination type is interface which source type implements
  • Support mapping from a type with more fields than the recipient
  • Extending the source type with other types, merging the properties into the resulting output
  • Prevent error on recursion
  • Handle destination types without a public default constructor
  • Map to normal method return type
  • Map collections

Future version

  • Method invocation mapping obj1.Method.MapInvoke(obj2);
  • Property assignment on existing object obj1.Map(obj2);
  • Map properties where source type has implicit conversion to destination type
  • Map properties where source type has explicit conversion to destination type
  • Support mapping to and from records

Features

This library grants all supported types a magical Map function which allows instances of the type to be converted to any type where each of the properties on the destination type can be matched by a property on the source type. A matching property with have the same name and type. The method will not exist until you type it out for the first time for a given source and destination type. If no implementation appears it means that no mapping could be made. This either means that the types do not support it, for example because they do not have the same properties or that the Map function has been used in an unsupported way. See Known Limitations for more info about the second case.

Example use:

var command = new CreateCustomerCommand(name, customerNumber);
Customer customer = command.Map();

Mapping to a type that is assignable from the source type simply returns the source instance.

The technical solution to implement the mapping is that Map returns object of an intermediary mapping type which has an implicit conversion operator to each recepient type.

Known Limitations

If the source class already has a Map() method, you cannot map from it.

You cannot map from types which are the product of another map operation. The reason for this limitation is that source generators cannot understand code generated by source generators, neither other generators nor itself. Since the return type of the Map method is resolved in the second compilation it cannot be understood by the source generator.

Since the return type of the Map method is determined based on how it is used, the library must handle all possible scenarios explicitly. There are bound to be edge cases which have been forgotten. If you run into such a case then create an issue and I will look into it. See the Roadmap sections for the supported scenarios. More scenarios may be supported by happy accident if they are similar enough to an existing case. Also, if a mathing mapping has already been generated from another use of the Map method, it will become avaiable everywhere regardless if it is supported.

Mapping to values in tuple types is particularly complex, so it is unlikely to make it into 1.0.

Mapping to and from interface types is not supported, since C# does not allow you to implement custom convertions for interfaces in either direction. This limitation is specific to the root type being mapped, not the properties of child objects.

Mapping to abstract types is not directly supported. You can work around this by mapping to a type having the desired base class somewhere else in your code. This mapping can also be used for the mapping to the abstract class.

Mapping of non-generic collections is not supported since there is no way to know that the actual types of the objects are.

Mapping of multidimensional arrays are consided too niche a use case and is therefore not supported.

Anonymous types are not support, neither for the Map nor the Extend method.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages