Skip to content

Commit 6667ce1

Browse files
Adds HasValue (#142)
* Ignores Rider * Adds HasValue which supports null check for nullable value types and objs * No need to capture, just use the existing value * Switches implementation After measuring the boxing path was more performant (both time and alloc) * Adds more tags to package
1 parent 4684853 commit 6667ce1

File tree

10 files changed

+168
-33
lines changed

10 files changed

+168
-33
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ packages/
2424
*.orig
2525
*.pfx
2626

27-
# resharper
27+
# resharper & rider
28+
.idea/
2829
_ReSharper.*
2930
*.resharper*
3031
*.[Rr]e[Ss]harper.user
32+
3133
*.DotSettings.user
3234

3335
#windows stuff

src/projects/EnsureThat/Enforcers/AnyArg.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
1+
using System;
12
using EnsureThat.Annotations;
23
using JetBrains.Annotations;
34

45
namespace EnsureThat.Enforcers
56
{
67
public sealed class AnyArg
78
{
9+
/// <summary>
10+
/// Ensures value is not null.
11+
/// Supports both <see cref="Nullable{T}"/> and reference types.
12+
/// If you know you are dealing with a certain type, e.g struct use preferred <see cref="IsNotNull{T}(T?, string, OptsFn)"/>
13+
/// overload instead as it is more performant.
14+
/// </summary>
15+
/// <typeparam name="T"></typeparam>
16+
/// <param name="value"></param>
17+
/// <param name="paramName"></param>
18+
/// <param name="optsFn"></param>
19+
/// <returns></returns>
20+
/// <remarks>If you know you are dealing with e.g. a struct, the <see cref="IsNotNull{T}(T?, string, OptsFn)"/> overload is more performant.</remarks>
21+
[NotNull]
22+
[ContractAnnotation("value:null => halt")]
23+
public T HasValue<T>([NoEnumeration, ValidatedNotNull] T value, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
24+
{
25+
// ReSharper disable once HeapView.BoxingAllocation
26+
if (value == null)
27+
throw Ensure.ExceptionFactory.ArgumentNullException(ExceptionMessages.Common_IsNotNull_Failed, paramName, optsFn);
28+
29+
return value;
30+
}
31+
832
[NotNull]
933
[ContractAnnotation("value:null => halt")]
1034
public T IsNotNull<T>([NoEnumeration, ValidatedNotNull] T value, [InvokerParameterName] string paramName = null, OptsFn optsFn = null) where T : class
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using EnsureThat.Annotations;
3+
using JetBrains.Annotations;
4+
5+
namespace EnsureThat
6+
{
7+
public static partial class EnsureArg
8+
{
9+
/// <summary>
10+
/// Ensures value is not null.
11+
/// Supports both <see cref="Nullable{T}"/> and reference types.
12+
/// If you know you are dealing with a certain type, e.g struct use preferred <see cref="IsNotNull{T}(T?, string, OptsFn)"/>
13+
/// overload instead as it is more performant.
14+
/// </summary>
15+
/// <typeparam name="T"></typeparam>
16+
/// <param name="value"></param>
17+
/// <param name="paramName"></param>
18+
/// <param name="optsFn"></param>
19+
/// <returns></returns>
20+
/// <remarks>If you know you are dealing with e.g. a struct, the <see cref="IsNotNull{T}(T?, string, OptsFn)"/> overload is more performant.</remarks>
21+
[NotNull]
22+
[ContractAnnotation("value:null => halt")]
23+
public static T HasValue<T>([NoEnumeration, ValidatedNotNull] T value, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
24+
=> Ensure.Any.HasValue(value, paramName, optsFn);
25+
26+
[NotNull]
27+
[ContractAnnotation("value:null => halt")]
28+
public static T IsNotNull<T>([NoEnumeration, ValidatedNotNull] T value, [InvokerParameterName] string paramName = null, OptsFn optsFn = null) where T : class
29+
=> Ensure.Any.IsNotNull(value, paramName, optsFn);
30+
}
31+
}

src/projects/EnsureThat/EnsureArg.Objects.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/projects/EnsureThat/EnsureThat.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>net4.5.1;netstandard1.1;netstandard2.0</TargetFrameworks>
55
<Title>Ensure.That</Title>
66
<PackageId>Ensure.That</PackageId>
7-
<PackageTags>ensure that argument validation guard clause contracts</PackageTags>
7+
<PackageTags>ensure-that ensure that argument validation guard clause contracts</PackageTags>
88
<PackageLicenseExpression>MIT</PackageLicenseExpression>
99
<AssemblyName>Ensure.That</AssemblyName>
1010
</PropertyGroup>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
3+
namespace EnsureThat
4+
{
5+
public static class EnsureThatAnyExtensions
6+
{
7+
/// <summary>
8+
/// Ensures value is not null.
9+
/// Supports both <see cref="Nullable{T}"/> and reference types.
10+
/// If you know you are dealing with a certain type, e.g struct use preferred <see cref="EnsureThatValueTypeExtensions.IsNotNull{T}(in Param{T?})"/>
11+
/// overload instead as it is more performant.
12+
/// </summary>
13+
/// <typeparam name="T"></typeparam>
14+
/// <param name="param"></param>
15+
/// <remarks>If you know you are dealing with e.g. a struct, the <see cref="EnsureThatValueTypeExtensions.IsNotNull{T}(in Param{T?})"/> overload is more performant.</remarks>
16+
public static void HasValue<T>(this in Param<T> param)
17+
=> Ensure.Any.HasValue(param.Value, param.Name, param.OptsFn);
18+
19+
public static void IsNotNull<T>(this in Param<T> param) where T : class
20+
=> Ensure.Any.IsNotNull(param.Value, param.Name, param.OptsFn);
21+
}
22+
}

src/projects/EnsureThat/EnsureThatObjectExtensions.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/tests/Benchmarks/Benchmarks.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp2.2</TargetFramework>
5+
<TargetFramework>netcoreapp3.0</TargetFramework>
66
<IsPackable>false</IsPackable>
7+
<LangVersion>7.3</LangVersion>
78
</PropertyGroup>
89

910
<ItemGroup>

src/tests/Benchmarks/Program.cs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ static void Main(string[] args)
1818

1919
public static class BaseLines
2020
{
21+
public static void NullableIntHasValue(int? value)
22+
{
23+
if (!value.HasValue)
24+
throw new ArgumentNullException(nameof(value));
25+
}
26+
27+
public static void StringIsNotNull(string value)
28+
{
29+
if (value == null)
30+
throw new ArgumentNullException(nameof(value));
31+
}
32+
2133
public static void StringIsNotNullOrWhiteSpace(string value)
2234
{
2335
if (value == null)
@@ -78,6 +90,8 @@ public static void ThingsHasItems<T>(List<T> things) where T : class
7890
//[CategoryFilter("Things.HasItems")]
7991
public class Ensures
8092
{
93+
private const string ParamName = "test";
94+
private static readonly int? NullableInt = 1;
8195
private readonly List<string> _strings = new List<string> { "test1", "TEST2", "Test3" };
8296
private readonly List<int> _ints = new List<int> { 1, 2, 3 };
8397
private readonly List<MyThing> _things = new List<MyThing>
@@ -112,7 +126,7 @@ public void StringIsNotNullOrWhiteSpaceViaThat()
112126
[Benchmark]
113127
[BenchmarkCategory("String.IsNotNullOrWhiteSpace")]
114128
public void StringIsNotNullOrWhiteSpaceViaEnforcer()
115-
=> Ensure.String.IsNotNullOrWhiteSpace("foo", "test");
129+
=> Ensure.String.IsNotNullOrWhiteSpace("foo", ParamName);
116130

117131
[Benchmark(Baseline = true)]
118132
[BenchmarkCategory("String.IsEqualTo")]
@@ -127,7 +141,7 @@ public void StringIsEqualToViaThat()
127141
[Benchmark]
128142
[BenchmarkCategory("String.IsEqualTo")]
129143
public void StringIsEqualToViaEnforcer()
130-
=> Ensure.String.IsEqualTo("foo", "foo", "test");
144+
=> Ensure.String.IsEqualTo("foo", "foo", ParamName);
131145

132146
[Benchmark(Baseline = true)]
133147
[BenchmarkCategory("Strings.HasItems")]
@@ -142,7 +156,7 @@ public void StringsHasItemsViaThat()
142156
[Benchmark]
143157
[BenchmarkCategory("Strings.HasItems")]
144158
public void StringsHasItemsViaEnforcer()
145-
=> Ensure.Collection.HasItems(_strings, "test");
159+
=> Ensure.Collection.HasItems(_strings, ParamName);
146160

147161
[Benchmark(Baseline = true)]
148162
[BenchmarkCategory("Int.Is")]
@@ -157,7 +171,7 @@ public void IntIsViaThat()
157171
[Benchmark]
158172
[BenchmarkCategory("Int.Is")]
159173
public void IntIsViaEnforcer()
160-
=> Ensure.Comparable.Is(42, 42, "test");
174+
=> Ensure.Comparable.Is(42, 42, ParamName);
161175

162176
[Benchmark(Baseline = true)]
163177
[BenchmarkCategory("Int.IsGt")]
@@ -172,7 +186,7 @@ public void IntIsGtViaThat()
172186
[Benchmark]
173187
[BenchmarkCategory("Int.IsGt")]
174188
public void IntIsGtViaEnforcer()
175-
=> Ensure.Comparable.IsGt(42, 41, "test");
189+
=> Ensure.Comparable.IsGt(42, 41, ParamName);
176190

177191
[Benchmark(Baseline = true)]
178192
[BenchmarkCategory("Ints.HasItems")]
@@ -187,7 +201,7 @@ public void IntsHasItemsViaThat()
187201
[Benchmark]
188202
[BenchmarkCategory("Ints.HasItems")]
189203
public void IntsHasItemsViaEnforcer()
190-
=> Ensure.Collection.HasItems(_ints, "test");
204+
=> Ensure.Collection.HasItems(_ints, ParamName);
191205

192206
[Benchmark(Baseline = true)]
193207
[BenchmarkCategory("Any.IsNotNull")]
@@ -202,7 +216,7 @@ public void ThingIsNotNullViaThat()
202216
[Benchmark]
203217
[BenchmarkCategory("Any.IsNotNull")]
204218
public void ThingIsNotNullViaEnforcer()
205-
=> Ensure.Any.IsNotNull(new MyThing(), "test");
219+
=> Ensure.Any.IsNotNull(new MyThing(), ParamName);
206220

207221
[Benchmark(Baseline = true)]
208222
[BenchmarkCategory("Things.HasItems")]
@@ -217,7 +231,32 @@ public void ThingsHasItemsViaThat()
217231
[Benchmark]
218232
[BenchmarkCategory("Things.HasItems")]
219233
public void ThingsHasItemsViaEnforcer()
220-
=> Ensure.Collection.HasItems(_things, "test");
234+
=> Ensure.Collection.HasItems(_things, ParamName);
235+
236+
[Benchmark(Baseline = true)]
237+
[BenchmarkCategory("Any.int.HasValue")]
238+
public void AnyHasValueWhenIntHasValueBaseLine()
239+
=> BaseLines.NullableIntHasValue(NullableInt);
240+
241+
[Benchmark]
242+
[BenchmarkCategory("Any.int.HasValue")]
243+
public void AnyHasValueWhenInt()
244+
=> Ensure.Any.HasValue(NullableInt, ParamName);
245+
246+
[Benchmark]
247+
[BenchmarkCategory("Any.int.HasValue")]
248+
public void AnyHasValueWhenIntViaNotNull()
249+
=> Ensure.Any.IsNotNull(NullableInt, ParamName);
250+
251+
[Benchmark(Baseline = true)]
252+
[BenchmarkCategory("Any.string.HasValue")]
253+
public void AnyHasValueWhenStringBaseLine()
254+
=> BaseLines.StringIsNotNull(string.Empty);
255+
256+
[Benchmark]
257+
[BenchmarkCategory("Any.string.HasValue")]
258+
public void AnyHasValueWhenString()
259+
=> Ensure.Any.HasValue(string.Empty, ParamName);
221260

222261
private class MyThing
223262
{

src/tests/UnitTests/EnsureObjectParamTests.cs renamed to src/tests/UnitTests/EnsureAnyParamTests.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,40 @@
44

55
namespace UnitTests
66
{
7-
public class EnsureObjectParamTests : UnitTestBase
7+
8+
public class EnsureAnyParamTests : UnitTestBase
89
{
10+
[Fact]
11+
public void HasValue_WhenNull_ThrowsArgumentNullException()
12+
{
13+
static void Verify<T>(T value) =>
14+
ShouldThrow<ArgumentNullException>(
15+
ExceptionMessages.Common_IsNotNull_Failed,
16+
() => Ensure.Any.HasValue(value, ParamName),
17+
() => EnsureArg.HasValue(value, ParamName),
18+
() => Ensure.That(value, ParamName).HasValue());
19+
20+
Verify((int?)null);
21+
Verify((string)null);
22+
Verify((Foo?)null);
23+
Verify((Type)null);
24+
}
25+
26+
[Fact]
27+
public void HasValue_WhenNotNull_ShouldNotThrow()
28+
{
29+
static void Verify<T>(T value) =>
30+
ShouldNotThrow(
31+
() => Ensure.Any.HasValue(value, ParamName),
32+
() => EnsureArg.HasValue(value, ParamName),
33+
() => Ensure.That(value, ParamName).HasValue());
34+
35+
Verify((int?)1);
36+
Verify("");
37+
Verify(Foo.Bar);
38+
Verify(typeof(int));
39+
}
40+
941
[Fact]
1042
public void IsNotNull_WhenRefTypeIsNull_ThrowsArgumentNullException()
1143
{
@@ -51,5 +83,10 @@ public void IsNotDefault_WhenIsNotDefault_ShouldNotThrow()
5183
() => EnsureArg.IsNotDefault(value, ParamName),
5284
() => Ensure.That(value, ParamName).IsNotDefault());
5385
}
86+
87+
private enum Foo
88+
{
89+
Bar
90+
}
5491
}
5592
}

0 commit comments

Comments
 (0)