Functional C#: Providing an Option Part 2
In my previous post I discussed creating an Option style construct for C#/.Net. This post is a followup with the complete code snippet. It’s been updated in response to several bits of feedback I received. Namely
- Option is now a struct vs. class
- Added equality metrics
- Allowing implicit conversion T –> Option<T>
As usual, this is available in the latest version of RantPack: https://code.msdn.microsoft.com/RantPack
[Immutable]
[Serializable]
[SuppressMessage("Microsoft.Naming", "CA1716")]
public struct Option<T> : IEquatable<Option<T>>
{
private readonly T m_value;
private readonly bool m_hasValue;
public static Option<T> Empty
{
get { return new Option<T>(); }
}
public bool HasValue
{
get { return m_hasValue; }
}
[DebuggerDisplay("m_value")]
public T Value
{
get
{
if (!HasValue)
{
throw new InvalidOperationException("Option does not have a value");
}
return m_value;
}
}
public T ValueOrDefault
{
get { return m_hasValue ? m_value : default(T); }
}
public Option(T value)
{
m_hasValue = true;
m_value = value;
}
#region Operators
[SuppressMessage("Microsoft.Usage", "CA1801")]
[SuppressMessage("Microsoft.Usage", "CA2225")]
public static implicit operator Option<T>(Option option)
{
return Option<T>.Empty;
}
[SuppressMessage("Microsoft.Usage", "CA1801")]
public static implicit operator Option<T>(T value)
{
return new Option<T>(value);
}
public static bool operator ==(Option<T> left, Option<T> right)
{
return left.Equals(right);
}
public static bool operator !=(Option<T> left, Option<T> right)
{
return !left.Equals(right);
}
#endregion
#region IEquatable<T> Members
public bool Equals(Option<T> other)
{
if (other.HasValue != this.HasValue)
{
return false;
}
// Both don't have a value
if (!other.HasValue)
{
return true;
}
return EqualityComparer<T>.Default.Equals(m_value, other.Value);
}
#endregion
#region Overrides
public override bool Equals(object obj)
{
if (obj is Option<T>)
{
return Equals((Option<T>)obj);
}
return false;
}
public override int GetHashCode()
{
if (!HasValue)
{
return 0;
}
return EqualityComparer<T>.Default.GetHashCode(m_value);
}
#endregion
}
[Immutable]
[Serializable]
[SuppressMessage("Microsoft.Naming", "CA1716")]
public sealed class Option
{
private static Option s_empty = new Option();
private Option()
{
}
public static Option<T> Create<T>(T value)
{
return new Option<T>(value);
}
public static Option Empty
{
get { return s_empty; }
}
}
Comments
Anonymous
October 08, 2008
PingBack from http://www.easycoded.com/functional-c-providing-an-option-part-2/Anonymous
October 30, 2008
Why do you need something this complicated? Just to have a unified way of coding between value and reference types? Because otherwise, value types can use T? (and test v.HasValue()) and reference types can use T and if (v != null).Anonymous
October 31, 2008
The comment has been removed