Bomret/NeverNull

Feature request: ToNullable() with select and ToOption() with map function

BADF00D opened this issue · 2 comments

In our domain we have some identifiers, that are currently represented by basic type like int?.
In order to make there more type safe, we decided to make custom identifiers.
E.g.

public sealed class ExternalCustomerId {
    public int Value {get;}
    /// private ctor and equals stuff ...
   ...
   public static ExternalCustomerId Create(int id){
      return new ExternalCustomerId(id);
   }
}

Our customer can be represented by:

public class Customer {
    public Option<ExternalCustomerId> {get;}
}

At our system boundaries, we have to map between our types and there basic type. The code for this is somewhat verbose and repetitive.

//to basic type
var externalId = customer.Id.Select(i => i.Value).ToNullable();
//to internal representation
var outId = externalId.ToOption().Select(ExternalCustomerId.Create);

In order to reduce the code form mapping, we wrote some extension methods:

    public static class TExtension {
        public static Option<TR> ToOptionMapped<T, TR>(this T? item, Func<T, TR> mapFn) where T : struct {
            return item.ToOption().Select(mapFn);
        }

        public static Option<TR> ToOptionMappedOrNoneIf<T, TR>(this T item, T nullValue, Func<T, TR> mapFn) where T : struct {
            return item.Equals(nullValue) ? Option<TR>.None : mapFn(item);
        }

        public static TR? ToNullable<T, TR>(this Option<T> item, Func<T, TR> selectFn) where TR : struct {
            return item.Select(selectFn).ToNullable();
        }
    }

//result
var externalId = customer.Id.ToNullable(i => i.Value);
var ourId = externalId.ToOptionMapped(ExternalCustomerId.Create);
//in case our third party system used magic values instead of Nullables
var externalId = 0; // 0  means no value
var ourId = externalId.ToOptionMappedOrNoneIf(0, ExternalCustomerId.Create);

What do you think? Is this something that can be a useful enhancement for the library?

I fixed the project's build process so feel free to add these and send a PR.

5.1.0 is released