如何克服泛型约束重载的C#限制?

时间:2014-09-09 15:53:19

标签: c# generics code-generation extension-methods fluent

让我们有以下代码(jQuery的类型安全存根):

public interface IjQueryPromise { }

public interface IjQueryPromise<TResult> : IjQueryPromise { }


public static class jQueryPromiseEx
{
    public static T Done<T>(this T t, params Action[] doneCallbacks)
        where T : IjQueryPromise { return t; } 

    public static T Done<T, TResult>(this T t, params Action<TResult>[] doneCallbacks)
        where T : IjQueryPromise<TResult> { return t; }
}

使用此代码,我试图允许调用:

  1. Done()IjQueryPromiseIjQueryPromise<TResult>
  2. 上无回调的回调
  3. Done()TResult上使用IjQueryPromise<TResult>类型的一个参数进行回调。
  4. 但是因为C#(v5.0)无法在泛型约束上重载,所以传递lambda就像:

    (r) => DoSomething(r) 
    

    会产生编译错误:

      

    委托'System.Action'不带1个参数。

    我将这些方法实现为扩展方法,以返回调用该函数的对象的类型。

    我唯一的想法是自动内联接口内的代码及其所有实现。

    是否有可能以更好的方式解决这个问题?

    或者是否已存在进行内联的工具?

    编辑:我正在为开发人员设计API。我知道我可以转发委托,但我不希望开发人员(API的用户)每次都被迫进行演员表。

2 个答案:

答案 0 :(得分:1)

这不是重载解决的问题。

与其他重载冲突无关。

这是类型推断的问题。如果您没有指明lambda的参数类型或整个委托的类型,那么您的第二次重载将无法推断TResult的类型。

通过简单地从应用程序中完全删除第一个重载,这很容易看到。所做的就是将错误信息从您所获得的内容更改为类型推断失败的错误信息。

你可以同时允许类型推断并且实际上不在其他地方提供任何类型信息(即为lambda参数键入输出类型)的一种方法是将其归结为一个通用参数:

public static IjQueryPromise<T> Done<T>(this IjQueryPromise<T> t,
    params Action<T>[] doneCallbacks)
{ return t; }

答案 1 :(得分:1)

问题是c#无法推断出匿名方法中参数的类型。

如果以这种方式声明参数类型,它将起作用;

IjQueryPromise<int> promise; 
promise.Done( (int r) => DoSomething(r) ); // This should work as expected