如何编写采用 Func<T,Task<T2>> 和 Func<T,T2> 而无需显式强制转换的重载
How to write overloads that takes Func<T,Task<T2>> and Func<T,T2> without explicit cast
我有一个方法有两个重载
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 的性质,它解开任务并使我的 Bar
等同于
T2 Bar(T input)
为了让它工作,我必须像这样显式地转换 //3
Foo((Func<T,Task<T2>>)Bar);
有什么优雅的方法可以避免这种显式转换吗?
更新
阐明 Foo
的目的
Foo() 不是调用委托的方法。它注册委托,委托将由不同的机制调用。
Foo() 没有类型参数的原因是因为类型参数是在 class 级别声明的。
可以在此处找到完整的模型代码https://dotnetfiddle.net/c6UCpi
我找到了一个非常优雅的解决方案:命名参数。
而不是调用
Foo(Bar);
我应该使用在 OP 中声明的显式命名参数来调用它。
Foo(asyncDelegate: Bar);
这明确告诉编译器使用异步重载并避免在没有显式转换的情况下产生歧义。
您面临的问题与 async/await 无关,而与签名仅 return 类型不同的方法有关。
这可以用这个简单的例子来证明:
static T2 Bar<T, T2>(T t)
{
return default(T2);
}
static IList<T2> Bar<T, T2>(T t)
{
return new List<T2>();
}
此代码将导致 Type 'Program' 已经定义了一个名为 'Bar' 且具有相同参数类型的成员 错误
这是没有任何内容的完整片段 async/await:
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();
}
我有一个方法有两个重载
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 的性质,它解开任务并使我的 Bar
等同于
T2 Bar(T input)
为了让它工作,我必须像这样显式地转换 //3
Foo((Func<T,Task<T2>>)Bar);
有什么优雅的方法可以避免这种显式转换吗?
更新 阐明 Foo
的目的Foo() 不是调用委托的方法。它注册委托,委托将由不同的机制调用。 Foo() 没有类型参数的原因是因为类型参数是在 class 级别声明的。
可以在此处找到完整的模型代码https://dotnetfiddle.net/c6UCpi
我找到了一个非常优雅的解决方案:命名参数。
而不是调用
Foo(Bar);
我应该使用在 OP 中声明的显式命名参数来调用它。
Foo(asyncDelegate: Bar);
这明确告诉编译器使用异步重载并避免在没有显式转换的情况下产生歧义。
您面临的问题与 async/await 无关,而与签名仅 return 类型不同的方法有关。
这可以用这个简单的例子来证明:
static T2 Bar<T, T2>(T t)
{
return default(T2);
}
static IList<T2> Bar<T, T2>(T t)
{
return new List<T2>();
}
此代码将导致 Type 'Program' 已经定义了一个名为 'Bar' 且具有相同参数类型的成员 错误
这是没有任何内容的完整片段 async/await:
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();
}