danielwertheim / ensure.that Goto Github PK
View Code? Open in Web Editor NEWGuard clause project for .NET
License: MIT License
Guard clause project for .NET
License: MIT License
Not all current [NotNull]
's are annotated, we should fill in any existing gaps. Also of particular use to users would be usage of the [InvokerParameterName]
which helps with auto-completion of the paramName
arguments.
I'd be happy to contribute this just opening an issue for tracking
Please add an extension method WithException(...) to define a custom exception to be thrown. It can be done today with Throws => Throws(x => x.Custom( ....)) but seems a little lengthy and not as fluent.
Thank you.
[DebuggerStepThrough]
[Conditional("notsatisfied")]
public static void AnyConditional<T>(this Param<IList<T>> param, Func<T, bool> predicate)
and benchmark confirms that even the That
is not run
This change would prevent the overhead (though minimal) of checking IsActive
ever, but would make Active/Inactive toggleable at the binary level only rather than dynamically at runtime (is dynamic a user requirement? I'm not sure of the uses cases for it)
Benchmark code:
private IList<string> strings;
public ArgumentValidation()
{
this.strings = new List<string>(10);
for (int i = 0; i < 9; i++)
{
this.strings.Add(string.Empty);
}
this.strings.Add(null);
}
[Benchmark]
public void AnyNoThrow()
{
try
{
Ensure.That(this.strings).Any(s => null == (s));
}
catch { }
}
[Benchmark]
public void AnyConditional()
{
Ensure.That(this.strings).AnyConditional(s => !string.IsNullOrEmpty(s));
}
[Benchmark]
public void BCLNoThrow()
{
var len = this.strings.Count;
for (int i = 0; i < len; i++)
{
if (null == (this.strings[i]))
{
return;
}
}
try {
throw new Exception();
}
catch { }
}
[Benchmark]
public void Baseline()
{
Ensure.That(this.strings);
}
The library appears to support IList, ICollection, and arrays, but IEnumerable should cover all of those bases, shouldn't it? Most of the collections I deal with are IEnumerable.
Great library!
It picks the 4.6 one according to comment in #16
One thing that would be nice is support for custom messages anywhere, maybe inside Param. Sometimes I may want the null check but may want to give a more informative, friendly exception message. Assuming there is nothing there for this currently best I can tell. Any ideas on this topic?
Many of the other methods like SizeIs, HasAny, etc in the CollectionArg
class expose a type-preserving API (e.g. where T : ICollection<TOther>
). Should ContainsKey
have the same for parity?
Also, other IDictionary
methods in this class contain an overload for IReadOnlyDictionary
explicitly; should this method?
The tests should point to the new flavor.
Oh dear
Today there's only check against that it is of a certain type, not the oposite.
Add new one to deal with null
case:
public static Param<T> That<T>(Func<T> expression, string name = "")
{
return new Param<T>(name, expression?.Invoke());
}
Preferably with an overload that takes advantage of ISet<T>
interface's optimization opportunities.
This method would ideally have an overload that takes in an IComparer<T>
argument.
Installed from NuGet:
package id="Ensure.That.Source" version="0.8.1" targetFramework="net40"
Most all code files generated the following error on compile:
The type or namespace name 'Resources' does not exist in the namespace 'EnsureThat' (are you missing an assembly reference?)
ExceptionMessages.resx is there now unlike the previous version but there is no designer code generated file. I was able to fix this manually via changing the properties of the resx project item:
Set custom tool to:
ResXFileCodeGenerator
Set custom tool namespace to:
EnsureThat.Resources
Was .Value removed due to some .NET standard limitation? Any plans to bring it back (i.e. net std 2.0)?
It's a bummer this doesn't appear to work anymore as it was handy:
_logger = Ensure.That(logger, nameof(logger)).IsNotNull().Value;
A quick pass with BenchmarkDotNet (I'm no expert though!)'s Jit Diagnoser suggested that the .That methods were unable to be inlined because their estimated size were too large. Argument validation is likely valid/desirable to inline, and addition of the attribute may assist.
To enable use of ConditionalAttribute
#70
Hi!
I am getting the following error: "Could not load file or assembly 'EnsureThat, Version=2.0.0.39118, Culture=neutral, PublicKeyToken=xxxxxxx' or one of its dependencies. The system cannot find the file specified" when calling to the constructor of MyCouch's MyCouchUriBuilder constructor.
Also I want to comment that in order to sign our project's installer, we sign MyCouch package with the package StrongNaming https://www.nuget.org/packages/Nivot.StrongNaming/
I've been using Pommalabs.Thrower as my guard clause library of choice for a while, but I've recently started using R# and I get quite a lot of warnings about possible enumeration of my IEnumerable method parameters when using Raise.ArgumentNullException.IfIsNull
.
I considered switching to using Ensure.That as I saw from your release notes that you handle this situation with Ensure.That(enumerable).IsNotNull()
. Unfortunately, this doesn't seem to have been implemented with the lighter-weight simple static methods that you've introduced in v5.0.0.
Having a brief look through your code base, I think that this could be resolved by creating a file EnsureArg.Enumerables.cs
:
using System;
using System.Diagnostics;
using JetBrains.Annotations;
namespace EnsureThat
{
public static partial class EnsureArg
{
[DebuggerStepThrough]
public static void IsNotNull<T>([NoEnumeration] IEnumerable<T> value, string paramName = Param.DefaultName)
{
if (!Ensure.IsActive)
return;
if (value == null)
throw new ArgumentNullException(paramName, ExceptionMessages.Common_IsNotNull_Failed);
}
}
}
Was it a some performance concern to keep just int?
Though here's a sample that would require a long
, via Enumerable.LongCount
perhaps, but I imagine it is only applicable in contrived scenarios and not applicable on ICollection
which exposes an int
Count
property, nor on IList
which exposes an int
this[]
accessor.
var myBigEnumerable = Enumerable.Range(0, int.MaxValue)
.Concat(Enumerable.Range(0, 10));
Ensure.Collection.SizeIs(
myBigEnumerable,
2147483657,
"paramName");
Some plugins like Exceptional
utilize the <exception>
xmldoc element to provide a type of checked-exceptions experience similar to java. Documenting the methods that can throw with the <exception>
element would enable those scenarios.
Was this performance based also or some other scenario? More of a question than issue π.
Thank you for your patience and explanations!
I have tons of unit tests in the same project verifying the arguments are valid throughout the project using Ensure.String.IsNotNullOrWhiteSpace(). They all expect an ArgumentNullException for null string values and an ArgumentException for empty or whitespace strings.
However, the empty/whitespace exceptions switch from ArgumentExceptions to ArgumentNullExceptions and back for no apparent reason. And when they switch, they are consistent within a class but not w/in the project. So 2 classes can use the exact same Ensure.String.IsNotNullOrWhitespace method for the exact same argument, but one class throws ArgumentExceptions and the other throws ArgumentNullExceptions.
In looking at the source code, this seems totally impossible; however, I can see the issue happening repeatedly. I haven't figured out how to intentionally cause the problem; however, that's to be expected b/c the behavior is clearly governed by something outside of my project b/c it switches w/out any changes to the project.
This is just a pain b/c a large number of unit tests start failing intermittently.
Only to IComparable<T>
E.g. ArgumentNotLessThanException with fields that expose the actual value and the validated against value.
make sure work here includes thoughts about how to handle the case where Directory method is called but a File exists at the path
Is(null)
probably suffices).SizeIs(0)
)IComparable
only)IComparable
only)May we have output assemblies signed with a Strong Name?
https://msdn.microsoft.com/en-us/library/xc31ft41(v=vs.110).aspx
EnsureArg.Booleans do not pass the OptsFn to the Ensure.Bool.IsTrue method.
https://github.com/danielwertheim/Ensure.That/blob/master/src/projects/EnsureThat/EnsureArg.Booleans.cs
Assembly name has changed from Ensure.That.dll
to EnsureThat.dll
which breaks other packages when resolved as third party dep. E.g: https://github.com/danielwertheim/mycouch/issues/132
I suggest that you add a new extension method IsNotDefault() that check the value is not the default one for the current type, especially for primitive types. it would simplify the check.
For instance, with a "int input", it would be
Ensure.That(input, "input").IsNotDefault();
Instead of :
Ensure.That(input, "input").IsNot(default(int));
Or maybe you already have something to handle that, but I couldn't find it.
Thanks !
I believe the motivating factor for deprecating the Ensure.That
syntax was the object allocation. A quick test with struct
seems that it may be as performant as the new static methods, and maintain the Ensure.That
syntax this library derives it's name from. I believe that the usage of Param<T>
will work within the constraints introduced by struct
also.
I can isolate the test change I did for a PR to send as proof of concept and include BenchmarkDotNet results for various scenarios. This issue is to track that work.
Add feature for: Ensure.That(dictionary).ContainsKey()
[DebuggerStepThrough]
public static Param<IDictionary<TKey, TValue>> ContainsKey<TKey, TValue>(this Param<IDictionary<TKey, TValue>> param, TKey key)
{
if (!param.Value.ContainsKey(key))
throw ExceptionFactory.CreateForParamValidation(param, $"Could not find key {key} in dictionary.");
return param;
}
"Ensuring that..." (i.e. the concept) applies to more than just arguments. I'm thinking specifically about state. For instance, I'd like to ensure that HttpContext.Current is not null, but I don't want to throw an argument exception if it is. I'd want to throw an InvalidOperationException. I'd suggest
public static class CustomExceptionExtensions
{
public static Param<T> WithExceptionOf<T>(this Param<T> param, Func<T> exceptionFn)
{
param.ExceptionFn = messageFn;
return param;
}
}
either that or add .State
after Ensure.That()
or something to cue the library to throw InvalidOperationException.
Hey,
rather than write your own extensions for each type, it would be more convenient if you put the constraints on the generic so that it goes on all numeric types.
like:
public static Param <TKey> IsLt<TKey> (Param param <TKey>, TKey limit) where TKey: struct, IComparable, IComparable <TKey>
{
if (param.Value> = limit) {
throw ExceptionFactory.CreateForParamValidation (param, ExceptionMessages.EnsureExtensions_IsNotLt.Inject (param.Value, limit));
}
return param;
}
So you have to deal with only the Nullable version for the following types. (date, float, double, byte, char, int16, int32, int64 + all unsigned versions)
public static Param <Nullable <TKey>> IsLt<TKey> (Param <Nullable <TKey>> param, TKey limit) where TKey: struct, IComparable, IComparable <TKey>
{
if (!param.Value.HasValue || param.Value.Value > = limit) {
throw ExceptionFactory.CreateForParamValidation (param, ExceptionMessages.EnsureExtensions_IsNotLt.Inject (param.Value, limit));
}
return param;
}
greets sam
Trying to include Ensure.That in a ASP.NET 5 / dnx46 project and receiving the following error about a missing assembly reference:
Error CS0012 The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Linq.Expressions, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
I am added the System.Linq.Expressions nugget package for the most recent (beta) version as well as the 4.0.10.0 version but that doesn't resolve the build error.
Is there something I need to do after installing the package? As soon as a guard "assertion" fails I get the below.
<System.Resources.MissingManifestResourceException> (Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "EnsureThat.Resources.ExceptionMessages.resources" was correctly embedded or linked into assembly "TestAssembly" at compile time, or that all the satellite assemblies required are loadable and fully signed.)
at System.Resources.ManifestBasedResourceGroveler.HandleResourceStreamMissing(String fileName)
at System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
...
The functions IsGt, IsLt, IsGte, IsLte, IsInRange all deal in ranges. I think a more appropriate exception to throw would be ArgumentOutOfRangeException.
Thoughts?
Currently, IsOfType
throws an exception when type of the passed object is different from the specified type.
However, it is often desired to see if an object is a subclass of a certain type. So, it could be useful if we can make IsOfType
optionally accept any subclass of the specified type rather than an instance that exactly matches it.
Hello @danielwertheim
First of all thank you for your library - it is really great.
Second one π
I spent some time on the performance improvements for lambda expressions and I want to share my results.
Compiling is slow operation for func, so I decided to replace it with the ExpressionVisitor and I got:
Name Milliseconds Percent
Ensure.That.Direct 7 916.9%
Ensure.That.Expression 489 59670.4%
Ensure.That.ThatAlternative1 36896 4500270%
Ensure.That.ThatAlternative2 37472 4570483.5%
Simple null check 0 100%
As you can see
Ensure.That(TestObject, "TestObject").IsNotNull()
is faster then
Ensure.That(() => TestObject).IsNotNull()
in ~70 times, but it is not so nice and clear πΈ
So we can change code in the main package, or I can create an extension and publish it to the nuget for the people, who want to have expressions in the Ensure.That?
Benchmark code (it uses https://github.com/bodyloss/BenchmarkIt) :
public class SimpleBenchmark
{
public TestObject TestObject { get; set; }
public SimpleBenchmark()
{
TestObject = new TestObject();
}
[Fact]
public void MyMethod()
{
Benchmark
.This("Ensure.That.Direct", () => Ensure.That(TestObject, "TestObject").IsNotNull())
.Against
.This("Ensure.That.Expression", () => Ensure.That(() => TestObject).IsNotNull())
.Against
.This("Ensure.That.ThatAlternative1", () => Extensions.ThatAlternative1(() => TestObject).IsNotNull())
.Against
.This("Ensure.That.ThatAlternative2", () => Extensions.ThatAlternative2(() => TestObject).IsNotNull())
.Against
.This("Simple null check", () =>
{
if (TestObject == null)
{
throw new ArgumentNullException("TestObject");
}
})
.WithWarmup(1000)
.For(100000)
.Iterations()
.PrintComparison();
}
}
cannot instead of can not
public static string Common_IsNotNull_Failed { get; private set; } = "Value can not be null.";
Please, add [ValidatedNotNull] to the arguments of the IsNotNull() methods in order to suppress the generation of warning CA1062: Validate arguments of public methods when Code Analysis is turned on and when EnsureThat is used for not null validation (more info here: https://esmithy.net/2011/03/15/suppressing-ca1062/).
Hi,
My app uses a recently released .NET Core 1.0 and it cannot compile with Ensure.That because of the different framework name:
The dependency Ensure.That 4.0.0 does not support framework .NETCoreApp,Version=v1.0.
Could you please add netcoreapp1.0 to the list of supported frameworks?
would be good if you don't let us to do the following
Ensure
.That(myString, nameof(myString))
.IsNotNullOrWhiteSpace()
.WithExtraMessageOf(p => "Some more details");
I created a gitter for less latent discussions. Use it or donβt as you feel appropriate! Iβll transfer ownership to you as soon as I learn how :)
Problem: Intellisense shows the IDictionary methods when I do Ensure.Collection, which are not valid on an ICollection
. Could we introduce a new DictionaryArg
class as a subclass of CollectionArg
?
Dear,
I am trying to use your library but I see that Ensure.That is going to be deprecated.
So I was curious on how I can do the following:
EnsureArg.IsFalse(true);
And have my own exception stating something like "value should be not true".
Hope you can help me out because I could not find it in the docs.
I notice new changes in the library around performance (specifically, the migration away from Ensure.That
to static methods and EnsureArg
). Given performance is important -- let's replace string.Empty.Equals(value) with value != null && string.IsNullOrEmpty(value)
BenchmarkDotNet micro benchmark showed this to be ~3x faster (intuitively makes sense as it doesn't have to deal with the overhead of equality just to see if it's empty - which I think the BCL uses .Length
to test)
To all args that can not be null.
Introduce as a more effective and simpler API but keep the old as well.
Can not use EnsureArg
from the existing as those might have decorations of e.g. WithException
. Dual track with duplicate tests?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.