【问题标题】:How do I declare a method using Func<T, TResult> as input argument?如何声明使用 Func<T, TResult> 作为输入参数的方法?
【发布时间】:2009-02-17 02:27:49
【问题描述】:

喂,

我正在编写一个可以帮助我进行单元测试的课程。该类提供了对异常执行断言的方法。

到目前为止,我能够编写将一个没有参数且没有返回值的函数作为输入的方法。为此,我使用 System.Action - 委托。 我的班级是这样的:

internal static class ExceptionAssert
{
    /// <summary>
    /// Checks to make sure that the input delegate throws a exception of type TException.
    /// <para>
    /// The input delegate must be a method with no parameters and return type void!
    /// </para>
    /// </summary>
    /// <typeparam name="TException">The type of exception expected.</typeparam>
    /// <param name="methodToExecute">The method to execute.</param>
    public static void Throws<TException>(Action methodToExecute) where TException : System.Exception
    {
        try
        {
            methodToExecute();
        }
        catch (Exception e)
        {
            Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
            return;
        }
        Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
    }

在单元测试中我现在可以写:

ExceptionAssert.Throws<ArgumentNullException>(theProxy.LoadProduct,productNumber); 

现在我想编写更多方法,这些方法将方法作为带有参数和返回值的输入。据我了解,通用 Func 应该服务于这个。并且方法签名应该是这样的:

public static void Throws<TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception

但这不会编译。我总是必须编写像 Func 这样的显式类型,而不是泛型。怎么了?应该可以用通用方式声明它,因为 LINQ 就是这样工作的。

编辑:

声明所有内容是个好主意,而不仅仅是一半。结果:

/// <summary>
/// Contains assertion types for exceptions that are not provided with the standard MSTest assertions.
/// </summary>
/// <typeparam name="T">The type of the input arguments.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <remarks>
/// The standard test framework has an Attribute called <see cref="ExpectedExceptionAttribute">ExpectedExceptionAttribute</see>. This attribute has two
/// main disadvantages:
/// <para>
/// 1. The unit test stops at the line which throws the expected exception. If you want to test a method which throws a bunch of exceptions
/// you must write a test for each exception.
/// 2. The attribute does not specify exactly where the exception has to be thrown. So if a method call earlier than expected throws
/// suddenly the same exception, the whole test is still o.k.
/// </para>
/// So this class can be used like the common assertions. You can test a method at a specific line in the test for a specific exception.
/// </remarks>
internal static class ExceptionAssert<T,TResult>
{
    /// <summary>
    /// Checks to make sure that the input delegate throws a exception of type TException.
    /// <para>
    /// The input delegate must be a method with no parameters and return type void!
    /// </para>
    /// </summary>
    /// <typeparam name="TException">The type of exception expected.</typeparam>
    /// <param name="methodToExecute">The method to execute.</param>
    public static void Throws<TException>(Action methodToExecute) where TException : System.Exception
    {
        try
        {
            methodToExecute();
        }
        catch (Exception e)
        {
            Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
            return;
        }
        Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
    }

    /// <summary>
    /// Checks to make sure that the input delegate throws a exception of type TException with a specific exception message.
    /// <para>
    /// The input delegate must be a method with no parameters and return type void!
    /// </para>
    /// </summary>
    /// <typeparam name="TException">The type of exception expected.</typeparam>
    /// <param name="expectedMessage">The expected exception message.</param>
    /// <param name="methodToExecute">The method to execute.</param>
    /// <remarks>
    /// This method asserts if the given message and the message of the thrown exception are not equal!
    /// </remarks>
    public static void Throws<TException>(string expectedMessage, Action methodToExecute) where TException : System.Exception
    {
        try
        {
            methodToExecute();
        }
        catch (Exception e)
        {
            Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
            Assert.AreEqual(expectedMessage, e.Message, "Expected exception with a message of '" + expectedMessage + "' but exception with message of '" + e.Message + "' was thrown instead.");
            return;
        }
        Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
    }


    /// <summary>
    /// Checks to make sure that the input delegate throws a exception of type TException with a specific exception message.
    /// <para>
    /// The input delegate must be a method with ONE parameter and return type!
    /// </para>
    /// </summary>
    /// <typeparam name="TException">The type of the exception.</typeparam>
    /// <param name="methodToExecute">The method to execute.</param>
    /// <param name="argument">The argument to input.</param>
    public static void Throws<TException>(Func<T,TResult> methodToExecute, T argument) 
        where TException : System.Exception
    {
        try
        {
            methodToExecute(argument);
        }
        catch (Exception e)
        {
            Assert.IsTrue(e.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + e.GetType() + " was thrown instead.");
            return;
        }
        Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
    }
}

【问题讨论】:

  • 它给你的错误是什么? “我总是必须编写像 Func 这样的显式类型而不是泛型”是什么意思

标签: c#-3.0 functional-programming


【解决方案1】:

您也应该“声明” T 和 TResult,例如

public static void Throws<T, TResult, TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception

否则编译器不知道 T 和 TResult 是什么。

【讨论】:

    【解决方案2】:

    这样编译:

     public static void Throws<TException, T, TResult>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
    

    这会给你想要的结果吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-08
      • 1970-01-01
      相关资源
      最近更新 更多