C# 3.0 如何使用Func<;声明方法;T、 TResult>;作为输入参数?

C# 3.0 如何使用Func<;声明方法;T、 TResult>;作为输入参数?,c#-3.0,functional-programming,C# 3.0,Functional Programming,Hy 我正在写一个类,它应该可以帮助我进行单元测试。该类提供了对异常执行断言的方法 到目前为止,我能够编写方法,这些方法将一个没有参数和返回值的函数作为输入。为此,我使用System.Action-delegates。 我的班级是这样的: internal static class ExceptionAssert { /// <summary> /// Checks to make sure that the input delegate throws a excep

Hy

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

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

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.");
    }
public static void Throws<TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
内部静态类异常assert
{
/// 
///检查以确保输入委托引发TexException类型的异常。
/// 
///输入委托必须是没有参数且返回类型为void的方法!
/// 
/// 
///应为异常的类型。
///要执行的方法。
公共静态void抛出(Action methodToExecute),其中TException:System.Exception
{
尝试
{
方法执行();
}
捕获(例外e)
{
Assert.IsTrue(e.GetType()==typeof(TException),“应为类型“+typeof(TException)+”的异常,但引发了类型“+e.GetType()+”);
回来
}
Assert.Fail(“类型为“+typeof(TException)+”的预期异常,但未引发异常。”);
}
在单元测试中,我现在可以写:

ExceptionAssert.Throws<ArgumentNullException>(theProxy.LoadProduct,productNumber); 
ExceptionAssert.Throws(proxy.LoadProduct,productNumber);
现在我想写更多的方法,这些方法将方法作为带有参数和返回值的输入。据我所知,泛型Func应该提供这种功能。方法签名应该如下所示:

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.");
    }
public static void Throws<TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
public static void抛出(Func methodToExecute,T methodArgument),其中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.");
    }
}
//
///包含标准MSTest断言未提供的异常的断言类型。
/// 
///输入参数的类型。
///结果的类型。
/// 
///标准测试框架有一个名为ExpectedExceptionAttribute的属性
///主要缺点:
/// 
///1.单元测试在抛出预期异常的行停止。如果您想测试抛出一系列异常的方法
///您必须为每个异常编写一个测试。
///2.该属性没有指定抛出异常的确切位置。因此,如果早于预期的方法调用抛出异常
///突然又出现了同样的异常,整个测试仍然正常。
/// 
///因此,这个类可以像普通断言一样使用。您可以在测试中的特定行测试一个方法,以获得特定的异常。
/// 
内部静态类异常Assert
{
/// 
///检查以确保输入委托引发TexException类型的异常。
/// 
///输入委托必须是没有参数且返回类型为void的方法!
/// 
/// 
///应为异常的类型。
///要执行的方法。
公共静态void抛出(Action methodToExecute),其中TException:System.Exception
{
尝试
{
methodToExecute();
}
捕获(例外e)
{
Assert.IsTrue(e.GetType()==typeof(TException),“应为类型“+typeof(TException)+”的异常,但引发了类型“+e.GetType()+”);
回来
}
Assert.Fail(“类型为“+typeof(TException)+”的预期异常,但未引发异常。”);
}
/// 
///检查以确保输入委托引发TexException类型的异常,并显示特定的异常消息。
/// 
///输入委托必须是没有参数且返回类型为void的方法!
/// 
/// 
///应为异常的类型。
///预期的异常消息。
///要执行的方法。
/// 
///如果给定消息和抛出异常的消息不相等,则此方法断言!
/// 
公共静态void抛出(字符串expectedMessage,Action methodToExecute),其中texException:System.Exception
{
尝试
{
方法执行();
}
捕获(例外e)
{
Assert.IsTrue(e.GetType()==typeof(TException),“应为类型“+typeof(TException)+”的异常,但引发了类型“+e.GetType()+”);
Assert.AreEqual(expectedMessage,e.Message,“消息为'+expectedMessage+''的预期异常,但消息为'+e.Message+''的异常被抛出。”);
回来
}
Assert.Fail(“类型为“+typeof(TException)+”的预期异常,但未引发异常。”);
}
/// 
///检查以确保输入委托引发TexException类型的异常,并显示特定的异常消息。
/// 
///输入委托必须是具有一个参数和返回类型的方法!
/// 
/// 
///异常的类型。
///要执行的方法。
///要输入的参数。
公共静态void抛出(Func methodToExecute,T参数)
其中TException:System.Exception
{
尝试
{
方法执行(论证);
}
捕获(例外e)
{
Assert.IsTrue(e.GetType()==typeof(TException),“应为类型“+typeof(TException)+”的异常,但引发了类型“+e.GetType()+”);
回来
}
Assert.Fail(“类型为“+typeof(TException)+”的预期异常,但未引发异常。”);
}
}
您还应该“声明”T和TResult,例如

public static void Throws<T, TResult, TException>(Func<T, TResult> methodToExecute, T methodArgument) where TException : System.Exception
public static void抛出(Func methodToExecute,T methodArgument),其中TException:System.Exception
否则编译器不知道T和TResult是什么