As anyone familiar wth C# knows, you cannot use the as
or is
keyword to change or check types with the out var
syntax.
For example, something like this is not possible:
var dictionary = new Dictionary<string, object>();
if (dictionary.TryGetValue("key", out as string val)) { }
This project aims to address the above desired use case.
Package manager console:
install-package tryget
Dotnet CLI:
dotnet add package tryget
using TryGet;
// Check if the key exists
if (dictionary.TryGet("key")) { }
// Check if the key exists and can be cast to string
if (dictionary.TryGet("key").As<string>()) { }
// Capture the value at key "key" if it exists and can be cast to string, otherwise default
var val = dictionary.TryGet("key").As<string>().OrDefault();
// Same as above, but with custom default value
var val = dictionary.TryGet("key").As<string>().OrDefault("Not a string.");
// Check if the key exists and capture the value with 'out' keyword
if (dictionary.TryGet("key").As<string>(out var val)) { }
Let's set up our dictionary.
TryGet works on any IDictionary<TKey, TValue>
, but it's most useful on <string, object>
dictionaries commonly used to pass custom data.
We will assume this dictionary exists for our examples.
var dictionary = new Dictionary<string, object>
{
{ "key", new { } },
{ "string", "This is a string." },
{ "number", 15 }
};
...exists
if (dictionary.TryGet("key"))
{
// "key" exists, do stuff
}
...exists and is of a certain type
if (dictionary.TryGet("string").As<string>())
{
// "string" exists and is a string
}
You can also check casts to polymorphic types.
class Animal { }
class Cat : Animal, IHasNineLives { }
class Dog : Animal { }
interface IHasNineLives { }
...
var animals = new Dictionary<string, Animal>
{
{ "cat", new Cat() },
{ "dog", new Dog() }
}
if (animals.TryGet("cat").As<Cat>())
{
// Success
}
if (animals.TryGet("cat").As<Dog>()}
{
// Not success
}
Interfaces work too
if (animals.TryGet("cat").As<IHasNineLives>())
{
// Success
}
if (animals.TryGet("dog").As<IHasNineLives>())
{
// Not success
}
I guess this works too if you're just a mad lad
if (animals.TryGet("cat").As<object>().As<Animal>().As<Cat>())
{
// Success
}
...if it exists
var val = dictionary.TryGet("number");
// val = 15 (boxed to an object)
...if it exists and is of a certain type, otherwise return the default
var val = dictionary.TryGet("number").As<int>().OrDefault();
// val = 15
var val = dictionary.TryGet("number").As<string>().OrDefault();
// val = null
OrDefault()
also supports custom default values
var val = dictionary.TryGet("number").As<string>().OrDefault("Not a string.");
// val = "Not a string."
You can also perform a check and capture the value with out
if (dictionary.TryGet("number").As(out var val))
{
// val = 15 (boxed to an object)
}
The real value-add here is being able to cast with out
if (dictionary.TryGet("number").As<int>(out var val)){
// val = 15
}
Calling .TryGet()
returns a result of type TryGetResult<TValue>
, which can be used directly instead of the fluent methods.
var result = dictionary.TryGet("number");
if (result.IsSuccess)
{
// Success!
// Do something with result.Value
}
The result also supports being cast directly to a compatible result type.
string stringValue = (string)result;
The only type you cannot cast to is bool
; this is a special case used for indicating success.
Value
will throw a NoValueException
if the key did not exist:
var result = dictionary.TryGet("does_not_exist");
var val = result.Value; // !!!
It will also throw a NoValueException
if the retrieved value was not the correct type:
var result = dictionary.TryGet("string").As<int>();
var val = result.Value; // !!!