Skip to content
Leonardo Porro edited this page Jan 31, 2024 · 6 revisions

Mapper types are classes implementing the IType interface that describes how .NET types (CLR Types) behaves in a mapping operation.

When mapping, some data or aspects not present in clr types are needed while others are discarded, IType adapts the CLR Type to the specific needs of the developer and the mapper by exposing the members needed by the mapper.

Implementing IType

In order to create a custom type adapter, specific members defined in IType interface must be implemented. JsonObjectTypeOptions.cs from Detached.Mappers.Json package is a good example of an IType implementation.

CrlType

All ITypes adapts a CLR Type to the mapper operation needs. At the end, everything is a CLR Type.

MappingSchema

Similar to Json objects, the mapper defines a simple mapping schema made of Primitives, Complexes and Collections. On the other hand, clr types doesn't have such a restriction, for example, string has a Length property, but is not a Complex, and is an enumeration of chars but is not a Collection. For mapping purposes, string is a Primitive. This property should be set to one of the supported schemas, or None if a customized TypeMapper is going to be introduced.

ItemClrType (Optional)

Some types have underlaying types, such as IEnumerable has elements or Nullable has a non-nullable base type. This property is useful to store that underlying type.

MemberNames

For Complexes only, the names of the members defined by this type. Some types define static members while others may have dynamic ones, so that, member names and GetMember() are two different functions, so that GetMember() allows to compute dynamic members. In a mapping operation, the mapper requires that at least 1 type to provide static members. There is no dynamic to dynamic implemented yet.

GetMember

Returns an ITypeMember implementation with metadata about a static or virtual member for the given member name.

BuildNewExpression

Returns an Expression that once compiled, it is used to create a new instance of the type.

Annotations

Stores metadata about the IType. Configuration stores different values and flags for TypeMappers here.

Implementing ITypeMember

Complexes have members, a member can be static such as the Property of a CLR Type, or dynamic, like an entry of a Dictionary<>. JsonObjectMemberOptions.cs from Detached.Mappers.Json package is a good example of a member implementation.

Name

Gets the name of the member, usually, PropertyInfo.Name name for class members and the same name provided in GetMember for dynamic members.

ClrType

Gets the member type. Usually PropertyInfo.PropertyType for class members and some other static type or Object for dynamic members.

CanRead

Whether the member has a getter.

CanWrite

Whether the member has a setter.

CanTryGet

If the member has a TryGetValue() method, such as Dictionary, the mapper will use it to get the value to be mapped. And if TryGetValue() returns false, no value will be set. This is useful to represent the 'undefined' state from json.

BuildGetExpression

This method should take an expression containing an instance of an object and build the expression to get the member from it. For example, it may take an expression of type User and build User.Name. Or it may take an expression of type Dictionary<string, object> and build User["Name"];

BuildSetExpression

This method should take an expression containing an instance of an object and build the expression to set the value of the member. For example, it may take an expression of type User and build User.Name = value. Or it may take an expression of type Dictionary<string, object> and build User["Name"] = value;

BuildTryGetExpression

For types supporting TryGetValue(), like Dictionary, this method should return a method call with the same signature that TryGetValue but not necessarily with that name.