C# 如何编写接受Func的重载<;T、 任务<;T2>&燃气轮机;和Func<;T、 T2>;没有显式强制转换

C# 如何编写接受Func的重载<;T、 任务<;T2>&燃气轮机;和Func<;T、 T2>;没有显式强制转换,c#,async-await,.net-4.6.1,C#,Async Await,.net 4.6.1,我有一个有两个重载的方法 void Foo(Func<T,T2> syncDelegate) {} //1 void Foo(Func<T,Task<T2>> asyncDelegate){} //2 由于async/await的性质,它打开任务并使我的Bar相当于 T2 Bar(T input) 为了让它工作,我必须像这样显式地强制转换//3 async Task<T2> Bar(T input) { // some await code h

我有一个有两个重载的方法

void Foo(Func<T,T2> syncDelegate) {} //1
void Foo(Func<T,Task<T2>> asyncDelegate){} //2
由于async/await的性质,它打开任务并使我的
Bar
相当于

T2 Bar(T input)
为了让它工作,我必须像这样显式地强制转换
//3

async Task<T2> Bar(T input)
{
// some await code here
}
Foo(Bar); //3
Foo((Func<T,Task<T2>>)Bar); 
Foo((Func)条);
有什么优雅的方法可以避免这种显式转换吗

更新 澄清Foo的目的

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


完整的模型代码可以在这里找到

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

而不是打电话

Foo(Bar);
我应该使用OP中声明的显式命名参数来调用它

Foo(asyncDelegate: Bar);
这显式地告诉编译器使用异步重载,避免在没有显式强制转换的情况下产生歧义

查看此完整代码段
我找到了一个非常优雅的解决方案:命名参数

而不是打电话

Foo(Bar);
我应该使用OP中声明的显式命名参数来调用它

Foo(asyncDelegate: Bar);
这显式地告诉编译器使用异步重载,避免在没有显式强制转换的情况下产生歧义

查看此完整代码段

您面临的问题不是async/await,而是带有签名的方法,这些签名只在返回类型上有所不同

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

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

static IList<T2> Bar<T, T2>(T t)
{
    return new List<T2>();
}
静态T2条(T)
{
返回默认值(T2);
}
静态IList条(T)
{
返回新列表();
}
此代码将导致类型“Program”已经定义了一个名为“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();
    }
静态t2foo(函数d1)
{
返回d1(默认值(T));
}
静态IList Foo(功能d2)
{
返回d2(默认值(T));
}
静态IList条(T)
{
Write($“Bar:{typeof(T).Name}->{typeof(T2).Name}:'{default(T)}'->'{default(T2)}'”;
返回新列表();
}
静态void Main(字符串[]参数)
{
//错误:以下方法或属性之间的调用不明确:“Program.Foo(Func)”和“Program.Foo(Func)”
//富(巴);;
//打印:Bar:String->Int32:''->“0”
Foo(d2:Bar);;
Console.ReadLine();
}

您面临的问题不是async/await,而是签名只因返回类型不同而不同的方法

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

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

static IList<T2> Bar<T, T2>(T t)
{
    return new List<T2>();
}
静态T2条(T)
{
返回默认值(T2);
}
静态IList条(T)
{
返回新列表();
}
此代码将导致类型“Program”已经定义了一个名为“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();
    }
静态t2foo(函数d1)
{
返回d1(默认值(T));
}
静态IList Foo(功能d2)
{
返回d2(默认值(T));
}
静态IList条(T)
{
Write($“Bar:{typeof(T).Name}->{typeof(T2).Name}:'{default(T)}'->'{default(T2)}'”;
返回新列表();
}
静态void Main(字符串[]参数)
{
//错误:以下方法或属性之间的调用不明确:“Program.Foo(Func)”和“Program.Foo(Func)”
//富(巴);;
//打印:Bar:String->Int32:''->“0”
Foo(d2:Bar);;
Console.ReadLine();
}

@LXL你能给我们源代码的链接吗?你在哪里找到asyncdelegate?@BRAHIMKamel,看看原始问题(上面)中两个Foo重载的函数签名。这两个重载有不同的参数名,显然类型推断考虑到了这一点。这个解决方案与给定的示例相同。@JohnWu您的版本与我的不同。我在类级别而不是方法级别定义了类型参数。因此,编译器能够推断T和T2@DaveM如果没有在类级别声明类型参数。如果您这样调用Foo,John Wu的示例仍然有效:
Foo(asyncDelegate:Bar)你在哪里告诉编译器T和T2@LXL的类型你能给我们源代码的链接吗?你在哪里找到asyncdelegate?@BRAHIMKamel,看看原始问题(上面)中两个Foo重载的函数签名。这两个重载有不同的参数名,显然类型推断考虑到了这一点。这个解决方案与给定的示例相同。@JohnWu您的版本与我的不同。我在类级别而不是方法级别定义了类型参数。因此,编译器能够推断T和T2@DaveM如果没有在类级别声明类型参数。如果您这样调用Foo,John Wu的示例仍然有效:
Foo(asyncDelegate:Bar)告诉编译器T和T2T的类型都是Foos异步的?异步方法应使用“Async”进行后期修复。@tymtam Foos不是异步方法。它所做的是注册委托,委托稍后将由不同的机制调用。这两个foo都是异步的吗?异步方法应使用“Async”进行后期修复。@tymtam Foos不是异步方法。它所做的是注册委托,委托稍后将通过不同的机制调用。我说“由于异步/等待的性质,它打开任务并使我的Bar等效于T2 Bar(T输入)”,您误解了我的说法。我没有在代码中声明为t2bar(t输入)的任何方法。因此,您的示例完全偏离了OPI,您误解了我的说法,因为我说“由于异步/等待的性质,它打开任务并使我的Bar等效于T2 Bar(T输入)”。我没有在代码中声明为t2bar(t输入)的任何方法。因此,你的例子完全不同于