using System.Collections.Generic;
public class Maybe<TSomething>
private readonly TSomething? value;
public bool IsPresent { get; }
private Maybe(TSomething value, bool isPresent)
this.IsPresent = isPresent;
public static readonly Maybe<TSomething> Empty = new(default!, false);
public static Maybe<TSomething> Of(TSomething value) => value != null ? new Maybe<TSomething>(value, true) : Empty;
public TSomething GetOrThrow() =>
IsPresent ? value! : throw new ArgumentNullException(nameof(value));
public TSomething GetOrDefault(TSomething defaultValue = default!) =>
IsPresent ? value ?? defaultValue : defaultValue;
public class Either<TLeft, TRight>
public Maybe<TLeft> Left { get; }
public Maybe<TRight> Right { get; }
public Either(TLeft value)
Left = Maybe<TLeft>.Of(value);
Right = Maybe<TRight>.Empty;
public Either(TRight value)
Left = Maybe<TLeft>.Empty;
Right = Maybe<TRight>.Of(value);
public Either(Maybe<TLeft> left, Maybe<TRight> right)
if (!left.IsPresent && !right.IsPresent)
throw new ArgumentOutOfRangeException(nameof(right));
public TMapped Map<TMapped>(
Func<TLeft, TMapped> mapLeft,
Func<TRight, TMapped> mapRight
return mapLeft(Left.GetOrThrow());
return mapRight(Right.GetOrThrow());
throw new Exception("That should never happen!");
onLeft(Left.GetOrThrow());
onRight(Right.GetOrThrow());
throw new Exception("That should never happen!");
private readonly string _nameEvent;
protected BaseEvent(string nameEvent)
public virtual string GetNameLogEvent() => _nameEvent.ToLower();
public class TestData : BaseEvent
public TestType testType { get; set; }
public double costInCash { get; set; }
public int newLevel { get; set; }
public int perUpgradeLevel { get; set; }
this.testType = testType;
this.costInCash = costInCash;
this.newLevel = newLevel;
this.perUpgradeLevel = perUpgradeLevel;
public static class Helpers {
public static bool IsNumber(this object value)
static void Main(string[] args) {
var levelUpgradeData = new TestData(
var dictionary = new Dictionary<string, Either<string, double>>();
Type myType = levelUpgradeData.GetType();
PropertyInfo[] props = myType.GetProperties();
foreach (var prop in props)
object propValue = prop.GetValue(levelUpgradeData, null);
dictionary.Add(prop.Name, new Either<string, double>((string) propValue));
else if (propValue is Enum)
var name = Enum.GetName(propValue.GetType(), propValue);
dictionary.Add(prop.Name, new Either<string, double>((string) name));
else if (Helpers.IsNumber(propValue))
var tempDouble = Convert.ToDouble(propValue);
dictionary.Add(prop.Name, new Either<string, double>((double) tempDouble));
foreach (KeyValuePair<string, Either<string, double>> item in dictionary)
onLeft: (stringValue) => {
Console.WriteLine($"String: {item.Key}={stringValue}");
onRight: (doubleValue) => {
Console.WriteLine($"Double: {item.Key}={doubleValue}");
Console.WriteLine("Done");