优化验证码(避免重复检查)

时间:2014-08-25 23:21:31

标签: c# .net performance

我更倾向于在其构造函数中验证类,但有时我会为某些低级类执行此操作以解决性能问题。当我开始制作成千上万个这些简单对象中的10个时,我经常在更高级别的逻辑中验证它们的输入,即使它们也有构造函数验证(逻辑通常在方法中失败 - 在我进入类c&之前#39;职责范围)

我喜欢保留低级验证代码,因为如果我忘记了更高级别的捕获,它有助于调试。我也不想删除低级验证代码以使其更快,因为如果我实现创建这些类的新方法,事情可能会无声地或在意外时间失败。

到目前为止,我忽略了性能问题并始终使用类似的模式验证内部构造函数,如下面的示例代码所示(请参阅Validate.MustBeAbove<T>扩展方法)。我添加了一个简单而且非常天真的方法来禁用using语句中的验证,但它显然不是线程安全的,而且它仍然很慢(我假设方法调用正在占用大部分时间??)。

问题:

  1. 如何以避免线程锁定的方式实现BarContext,但是指示从c到#Dispose(),应该跳过Validations。?
  2. Profile_Case_2 如何更接近 Profile_Case_3 的效果?
  3. 我应该做什么&#34;不安全&#34;这些低级别类型的构造函数?
  4. 您应该能够将代码复制粘贴到新的控制台项目中并运行它。

    结果

    Test Passed
    Test Passed
    Radius = 123.4
    ~~~~~~~~~~~~~~~~~
    Ranked Results
    ~~~~~~~~~~~~~~~~~
    
    Method: "Profile_Case_3_UnSafeFooObject_ConstructorAssignment"
    Iterations = 100000, Warm Up Calls = 10
    Results: Elapsed = 888ms, Average = 0.008875ms
    
    Method: "Profile_Case_4_UnSafeFooObject_PublicFieldAssignment"
    Iterations = 100000, Warm Up Calls = 10
    Results: Elapsed = 924ms, Average = 0.009242ms
    
    Method: "Profile_Case_2_FooObject_Without_Constructor_Validation"
    Iterations = 100000, Warm Up Calls = 10
    Results: Elapsed = 1,640ms, Average = 0.016399ms
    
    Method: "Profile_Case_1__FooObject_With_Constructor_Validated"
    Iterations = 100000, Warm Up Calls = 10
    Results: Elapsed = 1,926ms, Average = 0.019259ms
    

    代码

    using FluentValidation;
    using Foos;
    using Performance;
    using ProfileScenarios;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Tests;
    
    namespace OptimizeValidation
    {
        class Program
        {
            // Constants
            const int WARM_UP_CALLS = 10;
            const int ITERATIONS = 100000;
            const int COUNT = 360;
    
            // Static for Debug
            static StringBuilder sb = new StringBuilder();
    
            // Main Entry Point
            static void Main(string[] args)
            {
                double Radius = 123.4;
                sb.AppendFormat("Radius = {0}\r\n", Radius);
    
                try
                {
                    // Inline Test Cases
                    Basic_Inline_Tests.FooObject_created_with_p_radius_of_negative_1_should_throw_ArgumentOutOfRangeException();
                    Basic_Inline_Tests.FooObject_created_with_p_radius_of_negative_1_in_unchecked_mode_should_not_throw();
                }
                catch (Exception ex)
                {
                    sb.AppendFormat("Unexpected Exception: {0}\r\n", ex.Message);
                }
    
                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_1__FooObject_With_Constructor_Validated",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                            {
                                List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_1__FooObject_With_Constructor_Validated(Radius, COUNT);
                                ListOfFoos.Clear();
                            });
    
                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_2_FooObject_Without_Constructor_Validation",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                            {
                                List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_2_FooObject_Without_Constructor_Validation(Radius, COUNT);
                                ListOfFoos.Clear();
                            });
    
                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_3_UnSafeFooObject_ConstructorAssignment",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                        {
                            List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_3_UnSafeFooObject_ConstructorAssignment(Radius, COUNT);
                            ListOfFoos.Clear();
                        });
    
                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_4_UnSafeFooObject_PublicFieldAssignment",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                        {
                            List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_4_UnSafeFooObject_PublicFieldAssignment(Radius, COUNT);
                            ListOfFoos.Clear();
                        });
    
                sb.AppendFormat("\r\n~~~~~~~~~~~~~~~~~\r\nRanked Results\r\n~~~~~~~~~~~~~~~~~\r\n{0}", Profiler.Ranked_Results(p_descending: false));
    
                Console.WriteLine(sb.ToString());
                Console.ReadKey();
            }
        }
    }
    
    namespace FluentValidation
    {
        public static class Validate
        {
            // Static Fields
            public static bool m_disabled;
    
            /// <summary>
            /// Validates the passed in parameter is above a specified limit, throwing a detailed exception message if the test fails.
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="p_parameter">Parameter to validate.</param>
            /// <param name="p_limit">Limit to test parameter against.</param>
            /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
            /// <param name="p_variableValueName">Name of limit variable, if limit is not hard-coded.</param>
            /// <exception cref="ArgumentOutOfRangeException"></exception>
            public static void MustBeAbove<T>(this IComparable<T> p_parameter, T p_limit, string p_name, string p_variableValueName = default(string))
                where T : struct
            {
                // Naive approach
                if (m_disabled)
                    return;
    
                if (p_parameter.CompareTo(p_limit) <= 0)
                    if (p_variableValueName != default(string))
                        throw
                            new
                                ArgumentOutOfRangeException(string.Format(
                                "Parameter must be greater than the value of \"{0}\" which was {1}, but \"{2}\" was {3}.",
                                p_variableValueName, p_limit, p_name, p_parameter), default(Exception));
                    else
                        throw
                            new
                                ArgumentOutOfRangeException(string.Format(
                                "Parameter must be greater than {0}, but \"{1}\" was {2}.",
                                p_limit, p_name, p_parameter), default(Exception));
            }
    
            // Some Class to control whether validation actually happens
            public class BarContext : IDisposable
            {
                // What goes here to get the current Thread|Task so that a flag
                // can indicate that validation was performed at a higher level
                // and doesn't need to be repeated?
                public BarContext()
                {
                    // Naive approach
                    m_disabled = true;
                }
    
                // Dispose
                public void Dispose()
                {
                    // Naive approach
                    m_disabled = false;
                }
            }
    
            // Some method to return a thread specific context object
            public static IDisposable UncheckedContext()
            {
                // What goes here?
                return
                    new BarContext();
            }
        }
    }
    namespace ProfileScenarios
    {
        public static class ProfileCases
        {
            // Profile Scenarios
            public static List<IFooObject> Profile_Case_1__FooObject_With_Constructor_Validated(double p_radius, int p_count)
            {
                // Validate
                p_radius
                    .MustBeAbove(0, "p_radius");
                p_count
                    .MustBeAbove(0, "p_count");
    
                var FooList = new List<IFooObject>(p_count);
    
                for (int i = 0; i < p_count; i++)
                    FooList.Add(new FooObject(p_radius, i));
    
                return
                    FooList;
            }
            public static List<IFooObject> Profile_Case_2_FooObject_Without_Constructor_Validation(double p_radius, int p_count)
            {
                // Validate
                p_radius
                    .MustBeAbove(0, "p_radius");
                p_count
                    .MustBeAbove(0, "p_count");
    
                var FooList = new List<IFooObject>(p_count);
    
                using (var UncheckedMode = Validate.UncheckedContext())
                {
                    for (int i = 0; i < p_count; i++)
                        FooList.Add(new FooObject(p_radius, i));
                }
    
                return
                    FooList;
            }
            public static List<IFooObject> Profile_Case_3_UnSafeFooObject_ConstructorAssignment(double p_radius, int p_count)
            {
                // Validate
                p_radius
                    .MustBeAbove(0, "p_radius");
                p_count
                    .MustBeAbove(0, "p_count");
    
                var FooList = new List<IFooObject>(p_count);
    
                for (int i = 0; i < p_count; i++)
                    FooList.Add(new UnSafeFooObject_ConstructorAssignment(p_radius, i));
    
                return
                    FooList;
            }
            public static List<IFooObject> Profile_Case_4_UnSafeFooObject_PublicFieldAssignment(double p_radius, int p_count)
            {
                // Validate
                p_radius
                    .MustBeAbove(0, "p_radius");
                p_count
                    .MustBeAbove(0, "p_count");
    
                var FooList = new List<IFooObject>(p_count);
    
                for (int i = 0; i < p_count; i++)
                {
                    var Foo = new UnSafeFooObject_PublicFieldAssignment();
                    Foo.Radius = p_radius;
                    Foo.Angle = i;
                    FooList.Add(Foo);
                }
    
                return
                    FooList;
            }
        }
    }
    namespace Tests
    {
        public static class Basic_Inline_Tests
        {
            public static void FooObject_created_with_p_radius_of_negative_1_should_throw_ArgumentOutOfRangeException()
            {
                try
                {
                    // Test
                    new FooObject(-1, 123);
    
                    // Test Failed
                    throw
                        new InvalidOperationException(
                            "FooObject created with p_radius of -1 should throw ArgumentOutOfRangeException.");
                }
                catch (ArgumentOutOfRangeException)
                {
                    // Test Passed
                    Console.WriteLine("Test Passed");
                }
            }
            public static void FooObject_created_with_p_radius_of_negative_1_in_unchecked_mode_should_not_throw()
            {
                try
                {
                    // Test
                    using (var UncheckedMode = Validate.UncheckedContext())
                    {
                        new FooObject(-1, 123);
                    }
                }
                catch (ArgumentOutOfRangeException ex)
                {
                    // Test Failed
                    throw
                        new InvalidOperationException(
                            "FooObject created in Unchecked Mode threw an exception.", ex);
                }
    
                // Test Passed
                Console.WriteLine("Test Passed");
            }
        }
    }
    namespace Foos
    {
        public interface IFooObject
        {
            /*Placeholder*/
        }
    
        public class FooObject : IFooObject
        {
            // Fields
            private double m_radius;
            private double m_angle;
    
            // Properties
            public double Radius { get { return m_radius; } }
            public double Angle { get { return m_angle; } }
    
            // Constructor
            public FooObject(double p_radius, double p_angle)
            {
                // Validate
                p_radius
                    .MustBeAbove(0, "p_radius");
    
                // Init
                m_radius = p_radius;
                m_angle = p_angle;
            }
        }
        public class UnSafeFooObject_ConstructorAssignment : IFooObject
        {
            // Fields
            private double m_radius;
            private double m_angle;
    
            // Properties
            public double Radius { get { return m_radius; } }
            public double Angle { get { return m_angle; } }
    
            // Constructor
            public UnSafeFooObject_ConstructorAssignment(double p_radius, double p_angle)
            {
                //// Validate
                //p_radius
                //    .MustBeAboveZero("p_radius");
    
                // Init
                m_radius = p_radius;
                m_angle = p_angle;
            }
        }
        public class UnSafeFooObject_PublicFieldAssignment : IFooObject
        {
            // Public Fields
            public double Radius;
            public double Angle;
        }
    }
    namespace Performance
    {
        public static class Profiler
        {
            // Fields
            private static List<ResultDetails> m_results = new List<ResultDetails>();
            private static readonly object m_syncObject = new object();
    
            // Properties
            public static string TimerInfo
            {
                get
                {
                    return
                        string.Format("Timer: Frequency = {0:N0}Hz, Resolution = {1:N0}ns\r\n",
                        Stopwatch.Frequency,
                        ((1000L * 1000L * 1000L) / Stopwatch.Frequency));
                }
            }
    
            // Methods
            public static string Benchmark(string p_methodName, int p_iterations, int p_warmUpCalls, Action p_action)
            {
                lock (m_syncObject)
                {
                    // Prepare Environment
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
    
                    // Warm Up
                    for (int i = 0; i < p_warmUpCalls; i++)
                        p_action();
    
                    // Profile
                    var Timer = Stopwatch.StartNew();
                    for (int i = 0; i < p_iterations; i++)
                        p_action();
    
                    Timer.Stop();
    
                    // Return Results
                    var Details = new StringBuilder();
                    var Ellapsed = Timer.Elapsed.TotalMilliseconds;
                    var Average = (Timer.Elapsed.TotalMilliseconds / (double)p_iterations);
    
                    Details
                        .AppendFormat("Method: \"{0}\"\r\n", p_methodName)
                        .AppendFormat("Iterations = {0:D}, Warm Up Calls = {1:D}\r\n", p_iterations, p_warmUpCalls)
                        .AppendFormat("Results: Elapsed = {0:N0}ms, Average = {1:N6}ms\r\n", Ellapsed, Average);
    
                    m_results.Add(new ResultDetails(Average, Details.ToString()));
    
                    return Details.ToString();
                }
            }
            public static string Ranked_Results(bool p_descending)
            {
                lock (m_syncObject)
                {
                    var sb = new StringBuilder();
                    var OrderedList = (p_descending) ? m_results.OrderByDescending(result => result.Average) : m_results.OrderBy(result => result.Average);
    
                    foreach (var Result in OrderedList)
                        sb.AppendLine(Result.Details);
    
                    return sb.ToString();
                }
            }
            public static void Clear()
            {
                lock (m_syncObject)
                {
                    m_results.Clear();
                }
            }
    
            // Child Class
            private class ResultDetails
            {
                public double Average { get; private set; }
                public string Details { get; private set; }
    
                public ResultDetails(double p_average, string p_details)
                {
                    Average = p_average;
                    Details = p_details;
                }
            }
        }
    }
    

2 个答案:

答案 0 :(得分:1)

它有点难看,但在昨天编写了探查器案例后,我意识到方法调用可能是验证代码中最重要的部分(请参阅&#34;天真&#34;方法2中的案例2)原帖...它对性能的影响非常小。)

这让我想到了#34;理想&#34;没有任何验证代码只会像普通的构造函数或属性赋值一样快......但我鄙视编译器指令禁用代码(我不惜一切代价避免使用它们)而且我还没有想过向下一个程序员指示重载意图的好方法(因为重载本身不具有唯一的名称)。

所以我选择了一个抛弃类,它只用于表示应该调用未经验证的构造函数而不是验证的构造函数。它非常非常接近理想的性能水平(请注意,我的OP结果处于调试模式,附带调试器,因为我忘了将其设置为发布。下面的结果来自没有附带调试器的发布版本,与OP相比,所有方法都更快。

我原来问题的答案是:

  

如何以避免线程锁定的方式实现BarContext,但是指示从c&#tor;到Dispose(),应该跳过Validations?

答:您可以将ThreadStatic变量设置为标志,但它需要在类之间进行协作以获得最佳性能。此外,在生成Task的情况下,该标志将不会继续,并且需要单独为每个子任务设置。

  

Profile_Case_2如何更接近Profile_Case_3的性能?

答:你必须首先避免调用,它似乎是验证代码中最重的部分。也就是说,即使是对ThreadStatic变量的评估也会导致与理想情况相比性能下降约30%,这表明这已经非常快速地发挥作用。

  

我应该做什么&#34;不安全&#34;这些低级别类型的构造函数?

答:是的,重载类构造函数以允许未经验证的参数赋值。您不会获得比基于测试更好的性能。使用具有明确名称的虚拟类来指示其强制过载的目的也有助于其他程序员理解代码的意图。

WARM_UP_CALLS = 10
ITERATIONS = 100000
COUNT = 360
Radius = 123.4
Test Passed: p_radius of -1 was invalid.
Test Passed: p_radius of -1 was ignored using unchecked mode.
Test Passed: p_radius of -1 was ignored by unsafe overload.
Test Passed: p_radius of -1 after dispose was invalid.

~~~~~~~~~~~~~~~~~
Ranked Results
~~~~~~~~~~~~~~~~~
Method: "Profile_Case_4_UnSafeFooObject_PublicFieldAssignment"
Iterations = 100000, Warm Up Calls = 10
Results: Elapsed = 666ms, Average = 0.006658ms, Efficiency = 100.00%

Method: "Profile_Case_5_FooObject_With_UnSafeOverload"
Iterations = 100000, Warm Up Calls = 10
Results: Elapsed = 670ms, Average = 0.006695ms, Efficiency = 99.44%

Method: "Profile_Case_3_UnSafeFooObject_ConstructorAssignment"
Iterations = 100000, Warm Up Calls = 10
Results: Elapsed = 674ms, Average = 0.006737ms, Efficiency = 98.83%

Method: "Profile_Case_2_FooObject_using_UnSafeFlag"
Iterations = 100000, Warm Up Calls = 10
Results: Elapsed = 898ms, Average = 0.008975ms, Efficiency = 74.18%

Method: "Profile_Case_1_FooObject_With_Constructor_Validation"
Iterations = 100000, Warm Up Calls = 10
Results: Elapsed = 1,081ms, Average = 0.010812ms, Efficiency = 61.58%


Press Escape to exit, or any other key to run again.
namespace FluentValidation
{
    public class ValidateOverload
    { }

    public static class Validate
    {
        // Static Fields
        public static ValidateOverload UnSafeOverload = new ValidateOverload();
        ...
    }
}

它略微打破了DRY原则,但目的很明确(我可以将验证版本称为: this() c,但由于调用,代码很难理解构造函数的顺序...所以我宁愿打破像这样的简单类的DRY原则。)

    // Constructor
    public FooObject(double p_radius, double p_angle)
    {
        // Validate
        p_radius
            .MustBeAbove(0, "p_radius");

        // Init
        m_radius = p_radius;
        m_angle = p_angle;
    }
    public FooObject(double p_radius, double p_angle, ValidateOverload p_uncheckedMode)
    {
        // Init
        m_radius = p_radius;
        m_angle = p_angle;
    }

来自OP的更新代码,请参阅Profile_Case_5

using FluentValidation;
using Foos;
using Performance;
using ProfileScenarios;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tests;

namespace OptimizeValidation
{
    class Program
    {
        // Constants
        const int WARM_UP_CALLS = 10;
        const int ITERATIONS = 100000;
        const int COUNT = 360;

        // Static for Debug
        static StringBuilder sb = new StringBuilder();

        // Main Entry Point
        static void Main(string[] args)
        {
            double Radius = 123.4;

            Console.WriteLine("WARM_UP_CALLS = {0}", WARM_UP_CALLS);
            Console.WriteLine("ITERATIONS = {0}", ITERATIONS);
            Console.WriteLine("COUNT = {0}", COUNT);
            Console.WriteLine("Radius = {0}", Radius);

            try
            {
                // Inline Test Cases
                Basic_Inline_Tests.FooObject_created_with_p_radius_of_negative_1_should_throw_ArgumentOutOfRangeException();
                Basic_Inline_Tests.FooObject_created_with_p_radius_of_negative_1_using_unchecked_mode_should_not_throw();
                Basic_Inline_Tests.FooObject_created_with_p_radius_of_negative_1_with_unsafe_overload_should_not_throw();
                Basic_Inline_Tests.FooObject_created_with_p_radius_of_negative_1_using_unchecked_mode_should_throw_after_dispose();
            }
            catch (Exception ex)
            {
                sb.AppendFormat("Unexpected Exception: {0}\r\n", ex.Message);
            }

            do
            {

                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_1_FooObject_With_Constructor_Validation",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                            {
                                List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_1_FooObject_With_Constructor_Validation(Radius, COUNT);
                                ListOfFoos.Clear();
                            });

                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_2_FooObject_using_UnSafeFlag",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                            {
                                List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_2_FooObject_using_UnSafeFlag(Radius, COUNT);
                                ListOfFoos.Clear();
                            });

                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_3_UnSafeFooObject_ConstructorAssignment",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                        {
                            List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_3_UnSafeFooObject_ConstructorAssignment(Radius, COUNT);
                            ListOfFoos.Clear();
                        });

                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_4_UnSafeFooObject_PublicFieldAssignment",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                        {
                            List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_4_UnSafeFooObject_PublicFieldAssignment(Radius, COUNT);
                            ListOfFoos.Clear();
                        });

                Profiler
                    .Benchmark(
                        p_methodName: "Profile_Case_5_FooObject_With_UnSafeOverload",
                        p_warmUpCalls: WARM_UP_CALLS,
                        p_iterations: ITERATIONS,
                        p_action: () =>
                        {
                            List<IFooObject> ListOfFoos = ProfileCases.Profile_Case_5_FooObject_With_UnSafeOverload(Radius, COUNT);
                            ListOfFoos.Clear();
                        });

                sb
                    .AppendFormat(
                        "\r\n~~~~~~~~~~~~~~~~~\r\nRanked Results\r\n~~~~~~~~~~~~~~~~~\r\n{0}",
                        Profiler.Ranked_Results(p_descending: false));

                Console.WriteLine(sb.ToString());
                Console.WriteLine("Press Escape to exit, or any other key to run again.");

                // Reset
                Profiler.Clear();
                sb.Clear();
            }
            while (Console.ReadKey().Key != ConsoleKey.Escape);
        }
    }
}

namespace FluentValidation
{
    public class ValidateOverload
    {
    }

    public static class Validate
    {
        // ThreadStatic see example code http://msdn.microsoft.com/en-us/library/system.threading.thread.setdata%28v=vs.110%29.aspx

        // Static Fields
        [ThreadStatic]
        public static bool UncheckedMode;
        public static ValidateOverload UnSafeOverload = new ValidateOverload();

        /// <summary>
        /// Validates the passed in parameter is above a specified limit, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_limit">Limit to test parameter against.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <param name="p_variableValueName">Name of limit variable, if limit is not hard-coded.</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static void MustBeAbove<T>(this IComparable<T> p_parameter, T p_limit, string p_name, string p_variableValueName = default(string))
            where T : struct
        {
            if (p_parameter.CompareTo(p_limit) <= 0)
                if (p_variableValueName != default(string))
                    throw
                        new
                            ArgumentOutOfRangeException(string.Format(
                            "Parameter must be greater than the value of \"{0}\" which was {1}, but \"{2}\" was {3}.",
                            p_variableValueName, p_limit, p_name, p_parameter), default(Exception));
                else
                    throw
                        new
                            ArgumentOutOfRangeException(string.Format(
                            "Parameter must be greater than {0}, but \"{1}\" was {2}.",
                            p_limit, p_name, p_parameter), default(Exception));
        }

        // Method
        internal static IDisposable UncheckedThreadContext()
        {
            return
                new UnCheckedContext();
        }

        private class UnCheckedContext : IDisposable
        {
            public UnCheckedContext()
            {
                UncheckedMode = true;
            }

            // Dispose
            public void Dispose()
            {
                UncheckedMode = false;
            }
        }
    }
}
namespace ProfileScenarios
{
    public static class ProfileCases
    {
        // Profile Scenarios
        public static List<IFooObject> Profile_Case_1_FooObject_With_Constructor_Validation(double p_radius, int p_count)
        {
            // Validate
            p_radius
                .MustBeAbove(0, "p_radius");
            p_count
                .MustBeAbove(0, "p_count");

            var FooList = new List<IFooObject>(p_count);

            for (int i = 0; i < p_count; i++)
                FooList.Add(new FooObject(p_radius, i));

            return
                FooList;
        }
        public static List<IFooObject> Profile_Case_2_FooObject_using_UnSafeFlag(double p_radius, int p_count)
        {
            // Validate
            p_radius
                .MustBeAbove(0, "p_radius");
            p_count
                .MustBeAbove(0, "p_count");

            var FooList = new List<IFooObject>(p_count);

            using (Validate.UncheckedThreadContext())
            {
                for (int i = 0; i < p_count; i++)
                    FooList.Add(new FooObject_IfUnChecked(p_radius, i));
            }

            return
                FooList;
        }
        public static List<IFooObject> Profile_Case_3_UnSafeFooObject_ConstructorAssignment(double p_radius, int p_count)
        {
            // Validate
            p_radius
                .MustBeAbove(0, "p_radius");
            p_count
                .MustBeAbove(0, "p_count");

            var FooList = new List<IFooObject>(p_count);

            for (int i = 0; i < p_count; i++)
                FooList.Add(new UnSafeFooObject_ConstructorAssignment(p_radius, i));

            return
                FooList;
        }
        public static List<IFooObject> Profile_Case_4_UnSafeFooObject_PublicFieldAssignment(double p_radius, int p_count)
        {
            // Validate
            p_radius
                .MustBeAbove(0, "p_radius");
            p_count
                .MustBeAbove(0, "p_count");

            var FooList = new List<IFooObject>(p_count);

            for (int i = 0; i < p_count; i++)
            {
                var Foo = new UnSafeFooObject_PublicFieldAssignment();
                Foo.Radius = p_radius;
                Foo.Angle = i;
                FooList.Add(Foo);
            }

            return
                FooList;
        }
        public static List<IFooObject> Profile_Case_5_FooObject_With_UnSafeOverload(double p_radius, int p_count)
        {
            // Validate
            p_radius
                .MustBeAbove(0, "p_radius");
            p_count
                .MustBeAbove(0, "p_count");

            var FooList = new List<IFooObject>(p_count);

            for (int i = 0; i < p_count; i++)
                FooList.Add(new FooObject(p_radius, i, Validate.UnSafeOverload));

            return
                FooList;
        }
    }
}
namespace Tests
{
    public static class Basic_Inline_Tests
    {
        public static void FooObject_created_with_p_radius_of_negative_1_should_throw_ArgumentOutOfRangeException()
        {
            try
            {
                // Test
                new FooObject(-1, 123);

                // Test Failed
                throw
                    new InvalidOperationException(
                        "FooObject created with p_radius of -1 should throw ArgumentOutOfRangeException.");
            }
            catch (ArgumentOutOfRangeException)
            {
                // Test Passed
                Console.WriteLine("Test Passed: p_radius of -1 was invalid.");
            }
        }
        public static void FooObject_created_with_p_radius_of_negative_1_using_unchecked_mode_should_not_throw()
        {
            try
            {
                // Test
                using (Validate.UncheckedThreadContext())
                {
                    new FooObject_IfUnChecked(-1, 123);
                }
            }
            catch (ArgumentOutOfRangeException ex)
            {
                // Test Failed
                throw
                    new InvalidOperationException(
                        "FooObject created using unchecked mode threw an unexpected exception.", ex);
            }

            // Test Passed
            Console.WriteLine("Test Passed: p_radius of -1 was ignored using unchecked mode.");
        }
        public static void FooObject_created_with_p_radius_of_negative_1_using_unchecked_mode_should_throw_after_dispose()
        {
            try
            {
                // Test
                using (Validate.UncheckedThreadContext())
                {
                    new FooObject_IfUnChecked(-1, 123);
                }

                new FooObject_IfUnChecked(-1, 123);

                // Test Failed
                throw
                    new InvalidOperationException(
                        "FooObject created with p_radius of -1 after dispose should throw ArgumentOutOfRangeException.");
            }
            catch (ArgumentOutOfRangeException)
            {
                // Test Passed
                Console.WriteLine("Test Passed: p_radius of -1 after dispose was invalid.");
            }
        }
        public static void FooObject_created_with_p_radius_of_negative_1_with_unsafe_overload_should_not_throw()
        {
            try
            {
                // Test
                new FooObject(-1, 123, Validate.UnSafeOverload);
            }
            catch (ArgumentOutOfRangeException ex)
            {
                // Test Failed
                throw
                    new InvalidOperationException(
                        "FooObject created with unsafe overload threw an unexpected exception.", ex);
            }

            // Test Passed
            Console.WriteLine("Test Passed: p_radius of -1 was ignored by unsafe overload.");
        }
    }
}
namespace Foos
{
    public interface IFooObject
    {
        /*Placeholder*/
    }

    public class FooObject : IFooObject
    {
        // Fields
        private double m_radius;
        private double m_angle;

        // Properties
        public double Radius { get { return m_radius; } }
        public double Angle { get { return m_angle; } }

        // Constructor
        public FooObject(double p_radius, double p_angle)
        {
            // Validate
            p_radius
                .MustBeAbove(0, "p_radius");

            // Init
            m_radius = p_radius;
            m_angle = p_angle;
        }
        public FooObject(double p_radius, double p_angle, ValidateOverload p_uncheckedMode)
        {
            // Init
            m_radius = p_radius;
            m_angle = p_angle;
        }
    }
    public class FooObject_IfUnChecked : IFooObject
    {
        // Fields
        private double m_radius;
        private double m_angle;

        // Properties
        public double Radius { get { return m_radius; } }
        public double Angle { get { return m_angle; } }

        // Constructor
        public FooObject_IfUnChecked(double p_radius, double p_angle)
        {
            // Validate
            if (!Validate.UncheckedMode)
            {
                p_radius
                    .MustBeAbove(0, "p_radius");
            }

            // Init
            m_radius = p_radius;
            m_angle = p_angle;
        }
    }
    public class UnSafeFooObject_ConstructorAssignment : IFooObject
    {
        // Fields
        private double m_radius;
        private double m_angle;

        // Properties
        public double Radius { get { return m_radius; } }
        public double Angle { get { return m_angle; } }

        // Constructor
        public UnSafeFooObject_ConstructorAssignment(double p_radius, double p_angle)
        {
            // Init
            m_radius = p_radius;
            m_angle = p_angle;
        }
    }
    public class UnSafeFooObject_PublicFieldAssignment : IFooObject
    {
        // Public Fields
        public double Radius;
        public double Angle;
    }
}
namespace Performance
{
    public static class Profiler
    {
        // Fields
        private static List<ResultDetails> m_results = new List<ResultDetails>();
        private static readonly object m_syncObject = new object();

        // Properties
        public static string TimerInfo
        {
            get
            {
                return
                    string.Format("Timer: Frequency = {0:N0}Hz, Resolution = {1:N0}ns\r\n",
                    Stopwatch.Frequency,
                    ((1000L * 1000L * 1000L) / Stopwatch.Frequency));
            }
        }

        // Methods
        public static string Benchmark(string p_methodName, int p_iterations, int p_warmUpCalls, Action p_action)
        {
            // Profiler example http://stackoverflow.com/a/1048708/1718702

            lock (m_syncObject)
            {
                // Prepare Environment
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();

                // Warm Up
                for (int i = 0; i < p_warmUpCalls; i++)
                    p_action();

                // Profile
                var MethodTimer = Stopwatch.StartNew();
                for (int i = 0; i < p_iterations; i++)
                    p_action();

                MethodTimer.Stop();

                // Return Results
                var Details = new StringBuilder();
                var Ellapsed = MethodTimer.Elapsed.TotalMilliseconds;
                var Average = (MethodTimer.Elapsed.TotalMilliseconds / (double)p_iterations);

                Details
                    .AppendFormat("Method: \"{0}\"\r\n", p_methodName)
                    .AppendFormat("Iterations = {0:D}, Warm Up Calls = {1:D}\r\n", p_iterations, p_warmUpCalls)
                    .AppendFormat("Results: Elapsed = {0:N0}ms, Average = {1:N6}ms\r\n", Ellapsed, Average);

                m_results.Add(new ResultDetails(Average, Details.ToString()));

                return Details.ToString();
            }
        }
        public static string Ranked_Results(bool p_descending)
        {
            lock (m_syncObject)
            {
                var sb = new StringBuilder();
                var OrderedList = (p_descending) ? m_results.OrderByDescending(result => result.Average) : m_results.OrderBy(result => result.Average);

                double FastestImplementation = OrderedList.Select(r => r.Average).Min();
                foreach (var Result in OrderedList)
                {
                    sb
                        .Append(Result.Details.TrimEnd())
                        .AppendFormat(", Efficiency = {0:N2}%", (FastestImplementation / Result.Average) * 100)
                        .AppendLine()
                        .AppendLine();
                }

                return sb.ToString();
            }
        }
        public static void Clear()
        {
            lock (m_syncObject)
            {
                m_results.Clear();
            }
        }

        // Child Class
        private class ResultDetails
        {
            public double Average { get; private set; }
            public string Details { get; private set; }

            public ResultDetails(double p_average, string p_details)
            {
                Average = p_average;
                Details = p_details;
            }
        }
    }
}

答案 1 :(得分:0)

您是否只想创建用于有条件地编译验证代码的编译器常量(“DEBUGCHECKED”)?您的发布版本(经过全面测试)可以省略该指令并获得性能优势,但在开发中(您希望会出现错误),您可以使用它来选择验证代码。