The convention in C# is to make two versions of the method: GetFoo that throws, and TryGetFoo that returns a bool and places the result in an out parameter
For example, with the C# dictionary, you can either do: foo = dictionary["foo"]; Or: if(dictionary.TryGet("foo", out foo))
If Option<T> is your preferred pattern then you should use a language where that is supported.
Trying to recreate Option<T> in languages without compiler null checking has issues because either there's a risk that the Option<T> is null, or the value inside of it is null.
For example, with the C# dictionary, you can either do: foo = dictionary["foo"]; Or: if(dictionary.TryGet("foo", out foo))
If Option<T> is your preferred pattern then you should use a language where that is supported.
Trying to recreate Option<T> in languages without compiler null checking has issues because either there's a risk that the Option<T> is null, or the value inside of it is null.