如何在不进行显式强制转换的情况下编写需要Func <t,task <t2 >>和Func <t,t2>的重载

时间:2018-08-01 21:47:48

标签: c# async-await .net-4.6.1

我有一个方法有两个重载

void Foo(Func<T,T2> syncDelegate) {} //1
void Foo(Func<T,Task<T2>> asyncDelegate){} //2

然后我有一个这样实现的Bar方法

async Task<T2> Bar(T input)
{
// some await code here
}

然后Foo这样被调用

Foo(Bar); //3

由于async / await的性质,它解开了Task并使我的Bar等效于

T2 Bar(T input)

要使其正常工作,我必须像这样显式投射//3

Foo((Func<T,Task<T2>>)Bar); 

是否有任何优雅的方法来避免这种显式转换?

更新 阐明Foo的目的

Foo()不是调用委托的方法。它注册委托,并且委托将通过不同的机制调用。 Foo()没有类型参数的原因是因为类型参数是在类级别声明的。

完整的样机代码可在此处https://dotnetfiddle.net/c6UCpi

中找到

2 个答案:

答案 0 :(得分:4)

我找到了一个非常优雅的解决方案:命名参数。

代替呼叫

Foo(Bar);

我应该使用在OP中声明的显式命名参数来调用它。

Foo(asyncDelegate: Bar);

这明确地告诉编译器使用异步重载,并且无需显式强制转换就可以避免歧义。

查看此内容以获取完整摘要 https://dotnetfiddle.net/c6UCpi

答案 1 :(得分:-1)

您面临的问题与异步/等待无关,而与具有仅返回类型不同的签名的方法有关。

这可以通过以下简单示例进行演示:

static T2 Bar<T, T2>(T t)
{
    return default(T2);
}

static IList<T2> Bar<T, T2>(T t)
{
    return new List<T2>();
}

此代码将导致类型“程序”已定义具有相同参数类型的名为“ Bar”的成员错误


这是一个完整的代码段,没有任何异步/等待:

    static T2 Foo<T, T2>(Func<T, T2> d1)
    {
        return d1(default(T));
    }
    static IList<T2> Foo<T, T2>(Func<T, IList<T2>> d2)
    {
        return d2(default(T));
    }

    static IList<T2> Bar<T, T2>(T t)
    {
        Console.Write($"Bar: {typeof(T).Name} -> {typeof(T2).Name}: '{default(T)}' -> '{default(T2)}'");
        return new List<T2>();
    }



    static void Main(string[] args)
    {
        //Error: The call is ambiguous between the following methods or properties: 'Program.Foo<T, T2>(Func<T, T2>)' and 'Program.Foo<T, T2>(Func<T, IList<T2>>)'
        //Foo<string, int>(Bar<string, int>);


        //Prints: Bar: String -> Int32: '' -> '0'
        Foo<string, int>(d2: Bar<string, int>);


        Console.ReadLine();
    }