I'm currently in the process of reducing some of the duplications I have in my application framework and I wonder what people think about the following extension method?
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ThrowExtensions
{
public static T ThrowIfNull<T>(this T instance) where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
if (instance == null)
{
throw new ArgumentNullException("instance", string.Format("Object reference of type '{0}' not set to an instance of an object.", typeof(T).FullName));
}
return instance;
}
}
Consider the following example.
I know that extension everything is not a good practice and that I should avoid it if possible but in this case it seems quite reasonable although not pretty.
protected bool Contains<TEntity>(TEntity entity) where TEntity : class
{
Contract.Requires(entity != null);
ObjectStateEntry entry;
bool exist = ((IObjectContextAdapter)_context).ObjectContext.ThrowIfNull().ObjectStateManager.ThrowIfNull().TryGetObjectStateEntry(entity, out entry);
return exist;
}
EDIT: I'm also thinking about changing ThrowIfNull with Try() or something that fits more to this context as a convention in the framework but I really like opinion about it, If you have a better alternative I'd be glad to hear about it, thank you!
Update: So far that's what I ended up with.
namespace EasyFront.Framework.Diagnostics.Contracts
{
using System;
using System.ComponentModel;
using System.Diagnostics.Contracts;
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ContractsExtensions
{
/// <summary>
/// Calls the code wrapped by the delegate when the subject is not pointing to null, otherwise, <see
/// cref="ArgumentNullException" /> is thrown.
/// </summary>
/// <remarks>
/// Eyal Shilony, 01/08/2012.
/// </remarks>
/// <typeparam name="TSubject"> The type of the subject to operate on. </typeparam>
/// <typeparam name="TResult"> The type of the result to return from the call. </typeparam>
/// <param name="subject"> The subject to operate on. </param>
/// <param name="func"> The function that should be invoked when the subject is not pointing to null. </param>
/// <returns> The result of the invoked function. </returns>
public static TResult SafeCall<TSubject, TResult>(this TSubject subject, Func<TSubject, TResult> func)
where TSubject : class
{
Contract.Requires(func != null);
if (subject == null)
{
ThrowArgumentNull<TSubject>();
}
return func(subject);
}
/// <summary>
/// Calls the code wrapped by the delegate when the subject is not pointing to null,
/// otherwise, <see cref="ArgumentNullException" /> is thrown.
/// </summary>
/// <remarks>
/// Eyal Shilony, 01/08/2012.
/// </remarks>
/// <typeparam name="TSubject"> The type of the subject to operate on. </typeparam>
/// <param name="subject"> The subject to operate on. </param>
/// <param name="func"> The function that should be invoked when the subject is not pointing to null. </param>
public static void SafeCall<TSubject>(this TSubject subject, Action<TSubject> func)
where TSubject : class
{
Contract.Requires(func != null);
if (subject == null)
{
ThrowArgumentNull<TSubject>();
}
func(subject);
}
/// <summary>
/// Ensures that the subject is not pointing to null and returns it, otherwise, <see cref="ArgumentNullException" /> is thrown.
/// </summary>
/// <remarks>
/// Eyal Shilony, 01/08/2012.
/// </remarks>
/// <typeparam name="TSubject"> The type of the subject to operate on. </typeparam>
/// <param name="subject"> The subject to operate on. </param>
/// <returns> The subject. </returns>
public static TSubject SafeReturn<TSubject>(this TSubject subject)
where TSubject : class
{
Contract.Ensures(Contract.Result<TSubject>() != null);
if (subject == null)
{
ThrowArgumentNull<TSubject>();
}
return subject;
}
private static void ThrowArgumentNull<TSubject>() where TSubject : class
{
// ReSharper disable NotResolvedInText
throw new ArgumentNullException("subject", string.Format("Object reference of type '{0}' not set to an instance of an object.", typeof(TSubject).FullName));
// ReSharper restore NotResolvedInText
}
}
}
Here is a list of pros and cons I've compiled.
Pros:
Cons:
Here is some code that I had to deal with.
var entity = Builder.Entity<User>();
entity.HasKey(u => u.Id);
entity.Property(u => u.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
entity.Property(u => u.DisplayName).IsRequired();
entity.Property(u => u.DisplayName).HasMaxLength(20);
entity.Property(u => u.Username).HasMaxLength(50);
entity.Property(u => u.Password).HasMaxLength(100);
entity.Property(u => u.Salt).HasMaxLength(100);
entity.Property(u => u.IP).HasMaxLength(20);
entity.Property(u => u.CreatingDate);
entity.Property(u => u.LastActivityDate);
entity.Property(u => u.LastLockoutDate);
entity.Property(u => u.LastLoginDate);
entity.Property(u => u.LastPasswordChangedDate);
The comments that made by Jeffrey were valuable so I just ignored the warnings using the ContractVerificationAttribute.