Skip to content

Commit

Permalink
Added misc extension methods IDictionary<object, object?>
Browse files Browse the repository at this point in the history
+ added .NET 6 unit test project
  • Loading branch information
abjerner committed Jul 2, 2023
1 parent ee2d02b commit 9fef978
Show file tree
Hide file tree
Showing 5 changed files with 370 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/Skybrud.Essentials.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29806.167
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Skybrud.Essentials", "Skybrud.Essentials\Skybrud.Essentials.csproj", "{EDEB8F09-B293-4D1B-BC36-AD6C8EF8D9BD}"
EndProject
Expand All @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject1", "TestProject1\TestProject1.csproj", "{8EAA7946-1878-4720-86F6-BEA03787ED8E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -26,6 +28,10 @@ Global
{A160E1D0-5C6E-414D-BA75-06CC12FBFCEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A160E1D0-5C6E-414D-BA75-06CC12FBFCEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A160E1D0-5C6E-414D-BA75-06CC12FBFCEF}.Release|Any CPU.Build.0 = Release|Any CPU
{8EAA7946-1878-4720-86F6-BEA03787ED8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EAA7946-1878-4720-86F6-BEA03787ED8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EAA7946-1878-4720-86F6-BEA03787ED8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EAA7946-1878-4720-86F6-BEA03787ED8E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
204 changes: 204 additions & 0 deletions src/Skybrud.Essentials/Collections/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;

namespace Skybrud.Essentials.Collections.Extensions {

/// <summary>
/// Static class with various dictionary related extension methods.
/// </summary>
public static class DictionaryExtensions {

/// <summary>
/// Returns the 32-bit integer value of the dictionary item with the specified <paramref name="key"/>. If a
/// matching dictionary doesn't exist or it's value can not be converted to a <see cref="int"/> value, <c>0</c>
/// is returned instead.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <returns>The <see cref="int"/> value if successful; otherwise, <c>0</c>.</returns>
public static int GetInt32(this IDictionary<object, object?>? dictionary, object key) {
return TryGetInt32(dictionary, key, out int result) ? result : 0;
}

/// <summary>
/// Returns the 32-bit integer value of the dictionary item with the specified <paramref name="key"/>. If a
/// matching dictionary doesn't exist or it's value can not be converted to a <see cref="int"/> value,
/// <see langword="null"/> is returned instead.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <returns>The <see cref="int"/> value if successful; otherwise, <see langword="null"/>.</returns>
public static int? GetInt32OrNull(this IDictionary<object, object?>? dictionary, object key) {
return TryGetInt32(dictionary, key, out int? result) ? result : null;
}

/// <summary>
/// Returns the 64-bit integer value of the dictionary item with the specified <paramref name="key"/>. If a
/// matching dictionary doesn't exist or it's value can not be converted to a <see cref="long"/> value, <c>0</c>
/// is returned instead.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <returns>The <see cref="long"/> value if successful; otherwise, <c>0</c>.</returns>
public static long GetInt64(this IDictionary<object, object?>? dictionary, object key) {
return TryGetInt64(dictionary, key, out long result) ? result : 0;
}

/// <summary>
/// Returns the 64-bit integer value of the dictionary item with the specified <paramref name="key"/>. If a
/// matching dictionary doesn't exist or it's value can not be converted to a <see cref="long"/> value,
/// <see langword="null"/> is returned instead.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <returns>The <see cref="long"/> value if successful; otherwise, <see langword="null"/>.</returns>
public static long? GetInt64OrNull(this IDictionary<object, object?>? dictionary, object key) {
return TryGetInt64(dictionary, key, out long? result) ? result : null;
}

/// <summary>
/// Returns the string value of the dictionary item with the specified <paramref name="key"/>. If a matching dictionary item is found, but the value isn't a <see cref="string"/>, the value s converted to it's culture invariant string representation. If a matching dictionary isn't found, <see langword="null"/> is returned instead.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <returns>The <see cref="string"/> value if successful; otherwise, <see langword="null"/>.</returns>
public static string? GetString(this IDictionary<object, object?>? dictionary, object key) {
return TryGetString(dictionary, key, out string? result) ? result : null;
}

/// <summary>
/// Attempts to get a 32-bit integer value (<see cref="int"/>) from the with the specified <paramref name="key"/>.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <param name="result">When this method returns, holds the <see cref="int"/> value if successful; otherwise, <c>0</c>.</param>
/// <returns><see langword="true"/> if successful; otherwise, <see langword="false"/>.</returns>
public static bool TryGetInt32(this IDictionary<object, object?>? dictionary, object key, out int result) {

if (dictionary is null || !dictionary.TryGetValue(key, out object? value)) {
result = default;
return false;
}

switch (value) {

case int number:
result = number;
return true;

case long longValue:
if (longValue is >= int.MinValue and <= int.MaxValue) {
result = (int) longValue;
return true;
}
result = default;
return false;

case string str:
return int.TryParse(str, out result);

default:
result = default;
return false;

}

}

/// <summary>
/// Attempts to get a 32-bit integer value (<see cref="int"/>) from the with the specified <paramref name="key"/>.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <param name="result">When this method returns, holds the <see cref="int"/> value if successful; otherwise, <see langword="null"/>.</param>
/// <returns><see langword="true"/> if successful; otherwise, <see langword="false"/>.</returns>
public static bool TryGetInt32(this IDictionary<object, object?>? dictionary, object key, [NotNullWhen(true)] out int? result) {

if (TryGetInt32(dictionary, key, out int value)) {
result = value;
return true;
}

result = null;
return false;

}

/// <summary>
/// Attempts to get a 64-bit integer value (<see cref="long"/>) from the with the specified <paramref name="key"/>.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <param name="result">When this method returns, holds the <see cref="long"/> value if successful; otherwise, <c>0</c>.</param>
/// <returns><see langword="true"/> if successful; otherwise, <see langword="false"/>.</returns>
public static bool TryGetInt64(this IDictionary<object, object?>? dictionary, object key, out long result) {

if (dictionary is null || !dictionary.TryGetValue(key, out object? value)) {
result = default;
return false;
}

switch (value) {

case int intValue:
result = intValue;
return true;

case long longValue:
result = longValue;
return true;

case string str:
return long.TryParse(str, default, CultureInfo.InvariantCulture, out result);

default:
result = default;
return false;

}

}

/// <summary>
/// Attempts to get a 64-bit integer value (<see cref="int"/>) from the with the specified <paramref name="key"/>.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <param name="result">When this method returns, holds the <see cref="long"/> value if successful; otherwise, <see langword="null"/>.</param>
/// <returns><see langword="true"/> if successful; otherwise, <see langword="false"/>.</returns>
public static bool TryGetInt64(this IDictionary<object, object?>? dictionary, object key, [NotNullWhen(true)] out long? result) {

if (TryGetInt64(dictionary, key, out long value)) {
result = value;
return true;
}

result = null;
return false;

}

/// <summary>
/// Attempts to get the string value with the specified <paramref name="key"/>.
/// </summary>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key of the dictionary item.</param>
/// <param name="result">When this method returns, holds the <see cref="string"/> value if successful; otherwise, <see langword="null"/>.</param>
/// <returns><see langword="true"/> if successful; otherwise, <see langword="false"/>.</returns>
public static bool TryGetString(this IDictionary<object, object?>? dictionary, object key, [NotNullWhen(true)] out string? result) {

if (dictionary is null || !dictionary.TryGetValue(key, out object? value)) {
result = null;
return false;
}

result = string.Format(CultureInfo.InvariantCulture, "{0}", value);
return true;


}

}

}
135 changes: 135 additions & 0 deletions src/TestProject1/Collections/DictionaryExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@

using Skybrud.Essentials.Collections.Extensions;

namespace TestProject1.Collections {

[TestClass]
public class DictionaryExtensionsTests {

[TestMethod]
public void GetInt32() {

Dictionary<object, object?> dictionary = new() {
{"number", 123},
{"long", 123L},
{"longMax", long.MaxValue},
{"string", "123"},
{"null", null}
};

int a = dictionary.GetInt32("number");
Assert.AreEqual(123, a, "#A");

int b = dictionary.GetInt32("long");
Assert.AreEqual(123, b, "#B");

int c = dictionary.GetInt32("longMax");
Assert.AreEqual(0, c, "#C");

int d = dictionary.GetInt32("string");
Assert.AreEqual(123, d, "#D");

int e = dictionary.GetInt32("null");
Assert.AreEqual(0, e, "#E");

int f = dictionary.GetInt32("nope");
Assert.AreEqual(0, f, "#F");

}

[TestMethod]
public void GetInt32OrNull() {

Dictionary<object, object?> dictionary = new() {
{"number", 123},
{"long", 123L},
{"longMax", long.MaxValue},
{"string", "123"},
{"null", null}
};

int? a = dictionary.GetInt32OrNull("number");
Assert.AreEqual(123, a, "#A");

int? b = dictionary.GetInt32OrNull("long");
Assert.AreEqual(123, b, "#B");

int? c = dictionary.GetInt32OrNull("longMax");
Assert.AreEqual(null, c, "#C");

int? d = dictionary.GetInt32OrNull("string");
Assert.AreEqual(123, d, "#D");

int? e = dictionary.GetInt32OrNull("null");
Assert.AreEqual(null, e, "#E");

int? f = dictionary.GetInt32OrNull("nope");
Assert.AreEqual(null, f, "#F");

}

[TestMethod]
public void GetInt64() {

Dictionary<object, object?> dictionary = new() {
{"number", 123},
{"long", 123L},
{"longMax", long.MaxValue},
{"string", "123"},
{"null", null}
};

long a = dictionary.GetInt64("number");
Assert.AreEqual(123, a, "#A");

long b = dictionary.GetInt64("long");
Assert.AreEqual(123, b, "#B");

long c = dictionary.GetInt64("longMax");
Assert.AreEqual(long.MaxValue, c, "#C");

long d = dictionary.GetInt64("string");
Assert.AreEqual(123, d, "#D");

long e = dictionary.GetInt64("null");
Assert.AreEqual(0, e, "#E");

long f = dictionary.GetInt64("nope");
Assert.AreEqual(0, f, "#F");

}

[TestMethod]
public void GetInt64OrNull() {

Dictionary<object, object?> dictionary = new() {
{"number", 123},
{"long", 123L},
{"longMax", long.MaxValue},
{"string", "123"},
{"null", null}
};

long? a = dictionary.GetInt64OrNull("number");
Assert.AreEqual(123, a, "#A");

long? b = dictionary.GetInt64OrNull("long");
Assert.AreEqual(123, b, "#B");

long? c = dictionary.GetInt64OrNull("longMax");
Assert.AreEqual(long.MaxValue, c, "#C");

long? d = dictionary.GetInt64OrNull("string");
Assert.AreEqual(123, d, "#D");

long? e = dictionary.GetInt64OrNull("null");
Assert.AreEqual(null, e, "#E");

long? f = dictionary.GetInt64OrNull("nope");
Assert.AreEqual(null, f, "#E");

}

}

}
22 changes: 22 additions & 0 deletions src/TestProject1/TestProject1.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Skybrud.Essentials\Skybrud.Essentials.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/TestProject1/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

0 comments on commit 9fef978

Please sign in to comment.