2014-10-18 44 views
4

我是一名程序员,我很懒。目前我正在使用C#中的一些OpenAL包装器。每次我调用OpenAL方法时,我都必须使用GetError来从OpenAL请求错误,如果有错误,我会抛出异常。直到我添加了一个包含以下功能的静态帮助类才花了很长时间:常规方法Action/Func的扩展方法

public static void Check() 
    { 
     ALError error; 
     if ((error = AL.GetError()) != ALError.NoError) 
      throw new InvalidOperationException(AL.GetErrorString(error)); 
    } 

这个工作了一段时间,但我想要更多。因此,一段时间后,我想出了以下方法:

public static void Call(Action function) 
    { 
     function(); 
     ALHelper.Check(); 
    } 

    public static void Call<TParameter>(Action<TParameter> function, TParameter parameter) 
    { 
     function(parameter); 
     ALHelper.Check(); 
    } 

    public static TReturn Eval<TReturn>(Func<TReturn> function) 
    { 
     var val = function(); 
     ALHelper.Check(); 
     return val; 
    } 

    public static TReturn Eval<TParameter, TReturn>(Func<TParameter, TReturn> function, TParameter parameter) 
    { 
     var val = function(parameter); 
     ALHelper.Check(); 
     return val; 
    } 

这个工作很大,但我还是不开心时的代码究竟如何看,所以我决定把它一步:我将上述方法转换为扩展方法。因为我知道我可以通过ActionFunc参数的方法,所以我认为它可以用于扩展方法,将丑陋的handles = ALHelper.Eval(AL.GenBuffers, amount)变成更优雅的handles = AL.GenBuffers.Eval(amount)

不幸的是,一旦我开始使用它,我受到了一个例外的欢迎:Expression表示一个method group', where a变量,'value' or'类型'是预期的。

有点伤心,这不起作用,我真的很好奇,为什么这不起作用。究竟是什么原因,您可以通过方法ActionFunc,但使用扩展方法不起作用?这是我正在使用的单声道编译器(.NET 4.0)的限制吗,还是有其他内容?

回答

1

当您编写handles = ALHelper.Eval(AL.GenBuffers, amount)时,AL.GenBuffers不是任何类型的代表。重载解决方案会考虑所有重载ALHelper.Eval,并确切找到表达式AL.GenBuffers可以转换的一个委托类型。

当你写handles = AL.GenBuffers.Eval(amount)AL.GenBuffers依然没有任何类型的委托,所以AL.GenBuffers.Eval不匹配任何方法和重载解析无法帮助找到最佳匹配。

原则上,您可以编写new Func<T, TResult>(AL.GenBuffers).Eval(...)扩展方法可以处理委托类型,但这比您已有的要糟糕。

这不是特定于单声道。

我会做的是创建一个类(比如说MyAL),并为所有AL的函数提供包装。呼叫者然后可以说handles = MyAL.GenBuffers(amount);

+0

非常感谢。我已经预料到与此类似的东西,但很高兴看到详细解释。我确实已经考虑为AL创建自己的包装类,它可能会帮助很多事情,但现在我会坚持将该函数作为参数传递。 – Tom 2014-10-18 13:05:32

2

我想你误解了扩展方法的概念。它们用于扩展类型。在这种情况下,AL.GenBuffers是一种方法,它不是FuncAction.它的签名可能与它们兼容,但并不意味着它是一种func或动作或任何其他类型的委托类型。在您的示例中,由于method group conversions,您可以将其传递为AL.GenBuffers。当编译器看到方法签名是兼容的时,它将它转换为delegate类型。