// Copyright (c) 2009 Andrew Nurse // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Globalization; using System.Linq.Expressions; using System.Diagnostics; namespace Utils { internal static class Arg { public static void NotNull(object value, string paramName) { if (value == null) { throw new ArgumentNullException(paramName); } } public static void NotNullOrEmpty(string value, string paramName) { if (String.IsNullOrEmpty(value)) { // Replace Resources.Error_StringArgumentNullOrEmpty with your own message OR // Set the "Error_StringArgumentNullOrEmpty" key in your project's resources file // (see the Project properties section) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.Error_StringArgumentNullOrEmpty, paramName), paramName); } } // Lambda contract checkers. These are less performant than the above, but enable refactoring and more compact code // They can be replaced by non-lambda versions in runtime code with the following Visual Studio regex replacement: // Find: ^{:b*}Arg\.{(NotNull)|(NotNullOrEmpty)}\(:b*\(:b*\):b*\=\>:b*{:i}:b*\):b*;:b*$ // Replace with: \1Arg.\2(\3, "\3"); // And to convert back: // Find: ^{:b*}Arg\.{(NotNull)|(NotNullOrEmpty)}\(:b*{:i}:b*\,:b*\":b*:i:b*\":b*\):b*;:b*$ // Replace with: \1Arg.\2(() => \3); public static void NotNullOrEmpty(Expression> paramExpr) { string paramName = GetParameterName(paramExpr); // Compile the lambda (to get the value) Func compiledLambda = paramExpr.Compile(); // Check for a string argument NotNullOrEmpty(compiledLambda(), paramName); } public static void NotNull(Expression> paramExpr) { string paramName = GetParameterName(paramExpr); // Compile the lambda (to get the value) Func compiledLambda = paramExpr.Compile(); // Run the contract check NotNull(compiledLambda(), paramName); } private static string GetParameterName(Expression> paramExpr) { LambdaExpression lambda = paramExpr as LambdaExpression; Debug.Assert(lambda != null, "The expression passed to NotNull must be a lambda containing a single variable reference"); MemberExpression paramRef = lambda.Body as MemberExpression; Debug.Assert(paramRef != null, "The expression passed to NotNull must be a lambda containing a single variable reference"); // Get the parameter name string paramName = paramRef.Member.Name; return paramName; } } }