Skip to content

Instantly share code, notes, and snippets.

@gunters63
Last active March 15, 2020 13:43
Show Gist options
  • Save gunters63/6381c43dd0ee29aa813985303bf70120 to your computer and use it in GitHub Desktop.
Save gunters63/6381c43dd0ee29aa813985303bf70120 to your computer and use it in GitHub Desktop.
Immutable classes
namespace ConsoleApp2
{
public class Fruit2
{
public string Color { get; }
public int SkinThickness { get; }
public static Fruit2 Create(Optional<string> color = default, Optional<int> skinThickness = default)
{
return DefaultInstance.With(
color: Optional.For(value: color.GetValueOrDefault(defaultValue: DefaultInstance.Color)),
skinThickness: Optional.For(value: skinThickness.GetValueOrDefault(defaultValue: DefaultInstance.SkinThickness))
);
}
public Fruit2 ChangeColor(string newColor)
{
if (newColor == Color)
return this;
// Generate domain event
return With(color: newColor);
}
private Fruit2(string color, int skinThickness)
{
Color = color;
SkinThickness = skinThickness;
}
private static Fruit2 GetDefault()
{
return new Fruit2(color: string.Empty, 0);
}
private static readonly Fruit2 DefaultInstance = GetDefault();
private Fruit2 With(Optional<string> color = default, Optional<int> skinThickness = default)
{
return new Fruit2(
color: color.GetValueOrDefault(defaultValue: Color),
skinThickness: skinThickness.GetValueOrDefault(defaultValue: SkinThickness));
}
}
}
using System.Diagnostics;
namespace ConsoleApp2
{
public static class Optional
{
[DebuggerStepThrough]
public static Optional<T> For<T>(T value)
{
return value;
}
}
}
using System.Diagnostics;
namespace ConsoleApp2
{
/// <summary>
/// A wrapper around optional parameters to capture whether they were specified or omitted.
/// An implicit operator is defined so no one has to explicitly create this struct.
/// </summary>
[DebuggerDisplay(value: "{IsDefined ? Value.ToString() : \"<missing>\",nq}")]
public struct Optional<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="Optional{T}"/> struct.
/// </summary>
/// <param name="value">The value to specify.</param>
[DebuggerStepThrough]
public Optional(T value)
{
IsDefined = true;
Value = value;
}
/// <summary>
/// Gets an instance that indicates the value was not specified.
/// </summary>
public static Optional<T> Missing
{
[DebuggerStepThrough]
get => new Optional<T>();
}
/// <summary>
/// Gets a value indicating whether the value was specified.
/// </summary>
public bool IsDefined { [DebuggerStepThrough] get; }
/// <summary>
/// Gets the specified value, or the default value for the type if <see cref="IsDefined"/> is <c>false</c>.
/// </summary>
public T Value { [DebuggerStepThrough] get; }
/// <summary>
/// Implicitly wraps the specified value as an Optional.
/// </summary>
[DebuggerStepThrough]
public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
/// <summary>
/// Gets the value that was given, or the specified fallback value if <see cref="IsDefined"/> is <c>false</c>.
/// </summary>
/// <param name="defaultValue">The default value to use if a value was not specified.</param>
/// <returns>The value.</returns>
[DebuggerStepThrough]
public T GetValueOrDefault(T defaultValue)
{
return IsDefined ? Value : defaultValue;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment