我使用泛型方法有很多Funcy乐趣(有趣).在大多数情况下,C#类型推断足够聪明,可以找出它必须在我的泛型方法上使用的泛型参数,但现在我有一个C#编译器不成功的设计,而我相信它可以成功找到正确的类型.
在这种情况下,有人能告诉我编译器是否有点愚蠢,还是有一个非常清楚的原因导致它无法推断我的泛型参数?
这是代码:
类和接口定义:
interface IQuery<TResult> { }
interface IQueryProcessor
{
TResult Process<TQuery, TResult>(TQuery query)
where TQuery : IQuery<TResult>;
}
class SomeQuery : IQuery<string>
{
}
Run Code Online (Sandbox Code Playgroud)
一些不编译的代码:
class Test
{
void Test(IQueryProcessor p)
{
var query = new SomeQuery();
// Does not compile :-(
p.Process(query);
// Must explicitly write all arguments
p.Process<SomeQuery, string>(query);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么是这样?我在这里错过了什么?
这是编译器错误消息(它不会给我们留下太多想象):
无法从用法中推断出方法IQueryProcessor.Process(TQuery)的类型参数.尝试显式指定类型参数.
我认为C#应该能够推断它的原因是由于以下原因:
IQuery<TResult>.IQuery<TResult>类型实现的版本才是IQuery<string>TResult必须的string.解
对我来说,最好的解决方案是更改IQueryProcessor界面并在实现中使用动态类型:
public interface IQueryProcessor
{
TResult Process<TResult>(IQuery<TResult> …Run Code Online (Sandbox Code Playgroud) 鉴于以下课程......
public abstract class FooBase<TBar> where TBar : BarBase{}
public abstract class BarBase{}
public class Bar1 : BarBase{}
public class Foo1 : FooBase<Bar1> {}
Run Code Online (Sandbox Code Playgroud)
......以及以下方法......
public TBar DoSomething<TFoo, TBar>(TFoo theFoo)
where TFoo : FooBase<TBar>
where TBar : BarBase
{
return default(TBar);
}
Run Code Online (Sandbox Code Playgroud)
为什么以下代码行不能表示返回类型?
Bar1 myBar = DoSomething(new Foo1());
Run Code Online (Sandbox Code Playgroud)
相反,我必须指定像这样的泛型类型......
Bar1 myBar = DoSomething<Foo1, Bar1>(new Foo1());
Run Code Online (Sandbox Code Playgroud) 我有以下方法:
public TResult Get<TGenericType, TResult>()
where TGenericType : SomeGenericType<TResult>
where TResult : IConvertible {
//...code that uses TGenericType...
//...code that sets someValue...
return (TResult) someValue;
}
Run Code Online (Sandbox Code Playgroud)
现在,这个方法的用户必须像这样使用它:
//Notice the duplicate int type specification
int number = Get<SomeGenericType<int>, int>();
Run Code Online (Sandbox Code Playgroud)
为什么我必须在方法定义中指定TResult?编译器已经知道了TResult,因为我在TGenericType中指定了它.理想情况下(如果C#编译器更聪明一点),我的方法看起来像这样:
public TResult Get<TGenericType>()
where TGenericType : SomeGenericType<TResult>
where TResult : IConvertible {
//...code that uses TGenericType...
//...code that sets someValue...
return (TResult) someValue;
}
Run Code Online (Sandbox Code Playgroud)
所以用户可以像这样简单地使用它:
//Much cleaner
int number = Get<SomeGenericType<int>>();
Run Code Online (Sandbox Code Playgroud)
有办法做我想做的事吗?