我的最终目标是获得一个可以采用任何其他功能的功能 - 例如
void RegisterHandler( Delegate function);
Run Code Online (Sandbox Code Playgroud)
但是 - 我希望能够在不进行任何转换或没有类型参数的情况下调用它 - 显然 Delegate 不起作用。如果我声明:
void RegisterHandler<T>( Func<T> function );
Run Code Online (Sandbox Code Playgroud)
然后它工作正常 - 这有效:
string Whatever() {return "hi";}
...
RegisterHandler( whatever );
Run Code Online (Sandbox Code Playgroud)
但是 - 一旦我输入参数,它就不起作用
void RegisterHandler<TParam1,TReturn>( Func<TParam1, TReturn> function );
string Something( int x ) {return x.ToString();}
...
RegisterHandler( Something ); // doesn't compile - wants types specified
RegisterHandler<int,string>( Something ); // works, but is what I'm trying to avoid
Run Code Online (Sandbox Code Playgroud)
如果“对象”有效,我什至没问题——这只是流畅界面的一部分,我只想能够调用它。我在某处读到参数的数量必须 >= 模板类型的数量,我猜返回类型被计算在内,所以我永远无法实现。
底线 - 我找不到任何c# 签名可以接受任何接受一个参数并返回某些内容的函数。是否可以?
Eri*_*ert 14
与其直接攻击你的问题,这需要一些澄清,让我在这里解决你的问题:
我在某处读到参数的数量必须 >= 模板类型的数量
让我们把它说清楚一点。
首先,这些是泛型类型参数,而不是“模板类型”。这不是 C++。泛型类似于模板,但它们不是模板,你越早停止将它们视为模板越好。
形式参数的数量需要大于或等于泛型方法声明的泛型类型参数的数量是不正确的。例如:
static void M<K, V>(Dictionary<K, V> d) { }
...
Dictionary<int, string> d = whatever;
M(d); // No problem!
Run Code Online (Sandbox Code Playgroud)
形式参数的数量是一个,泛型类型参数的数量是两个,但是我们在这里做类型推断是没有问题的。
真正的规则要复杂得多。相反,您遇到的真正问题是:
将方法组转换为委托要求在转换发生之前知道委托的参数类型。
假设我们有:
int F(string x) { ... }
void M<A, R>(Func<A, R> f) { ... }
M(F);
Run Code Online (Sandbox Code Playgroud)
发生什么了?我们必须确定转换为时 F 的含义,Func<A, R>但我们既不知道A也不知道R。我们如何确定意义? 我们做重载决议。也就是说,我们会假装有一个电话:
A a = whatever;
F(a)
Run Code Online (Sandbox Code Playgroud)
并问“哪个名为 F 的方法会起作用?”
但是,我们从来没有到达那一步,因为我们不知道什么A是还没有。类型推断未能取得进展。现在,如果相比之下你有:
int F(string x) { ... }
void M<A, R>(A a, Func<A, R> f) { ... }
M("abc", F);
Run Code Online (Sandbox Code Playgroud)
现在类型推断首先说“我从"abc"for athat Ais的使用中推导出来string。” 在进行推断之后,现在重载解析将成功。如果我们做了
string a = whatever;
F(a);
Run Code Online (Sandbox Code Playgroud)
那么重载决议将决定这F意味着int F(string)。
一旦我们确定了这F意味着int F(string),现在我们可以问这个问题“我们可以从int F(string)到的转换中推断出什么Func<string, R>,从中我们推断出R必须是int,我们就完成了。
我知道你接下来要问什么。 我只有一个名为 F 的重载,那么我们为什么不自动选择它呢?
像这样设置例外有很多问题。首先,特殊情况往往会成倍增加,很快我们就有了一个更疯狂的推理算法,没有人理解它,并且不能在不引起错误的情况下进行更改。其次,它使您的代码变得脆弱;这意味着推理取决于范围内名为 F 的可访问方法的数量。假设您添加了一个新的私有方法,也称为F; 推理会突然改变吗?
不,一旦你知道它的规则是简单易懂的。方法组的解析与调用方法完全相同。但是在推断出参数类型之前,我们无法模拟调用。
相信我,我和任何人一样知道 C# 中的类型推断算法有多么棘手;它有很多这种令人惊讶的案例。如果您对此算法的设计、实现或规范有更清晰的问题,请随时提出一个新问题,并在此答案上给我留言,我会尝试看看。