In C#, the following function compiles:
static double? Add(double? x, double? y)
{
return x + y;
}
Even though there is no addition operator defined for double?, or for Nullable<T> in general. But the C# compiler translates the above to:
static double? Add(double? x, double? y)
{
return x.HasValue && y.HasValue ? new double?(x.GetValueOrDefault() + y.GetValueOrDefault()) : null;
}
But I cannot write the following:
static double? Abs(double? x)
{
return Math.Abs(x); // won't compile
}
With a bit of Linq though, I can write the following:
static double? Abs(double? x)
{
return from d in x select Math.Abs(d);
}
All I need to make this work is the following extension method:
public static T? Select<T>(this T? x, Func<T, T> selector)
where T : struct
{
return x.HasValue ? new T?(selector(x.Value)) : null;
}
I could even add a Where extension method:
public static T? Where<T>(this T? source, Func<T, bool> predicate)
where T : struct
{
return source.HasValue && predicate(source.Value) ? source : null;
}
Which would allow weird (or cool?) stuff such as:
static double? Asin(double? x)
{
return from d in x where d >= -1 && d <= 1 select Math.Asin(d);
}
Toss in a SelectMany:
public static V? SelectMany<T, U, V>(this T? source, Func<T, U?> k, Func<T, U, V> resultSelector)
where T : struct
where U : struct
where V : struct
{
if (k == null)
{
throw new ArgumentNullException("k");
}
if (resultSelector == null)
{
throw new ArgumentNullException("resultSelector");
}
return source.HasValue && k(source.Value).HasValue ?
new V?(resultSelector(source.Value, k(source.Value).Value)) : null;
}
And now I can write:
static double? SinCos(double? x, double? y)
{
return from xd in x
from yd in y
select Math.Sin(xd) * Math.Cos(yd);
}
Who said Linq was about object-relational mappers? Or was it functional programming perhaps?