我有以下样本。
class Program {
static void Main(string[] args) {
var varc = new C();
// Error CS0411
var varf1b = varc.F1(t => new { City = t.City }, (t, v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });
// compiles OK
var varf1a = varc.F1(t => new { City = t.City }, (C t, int v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });
// now replace varc by an anonymous class -- how to solve it now?
var varanon = new { };
}
}
public class C {
public string City;
public int Status;
}
public static class X {
public static T1 F1<T2, T3, T4, T1>(
this T2 s,
Func<T2, T3> g,
Func<T2, T4, T4> a,
Func<T3, T4, T1> r)
where T2 : class where T3 : class where T1 : class {
return null;
}
}
第一个呼叫触发错误CS0411。我不能用通常的方法来解决这个问题,因为它使用了匿名类型。幸运的是,向其中一个lambda添加类型似乎足以让编译器满意。
为什么?具体是什么使第一个例子失败而第二个例子成功?
其次,是否有任何方法可以编写函数调用,这样就不会发生这种情况,并且用户不必面对必须在lambda中插入类型?
是的,其他人也提出了类似的问题,但这里的独特之处在于:(a)使用匿名类型(b)通过向lambda添加类型来修复。
编辑:给出的解决方案的问题是它不能与匿名类一起使用,因为没有可能的类型注释。
答案 0 :(得分:1)
问题是:v
的类型是什么?
编译器不会从用作输出的表达式推断输入的类型。编译器使用输入的推断类型来为输出编写有效的表达式。因此,(t, v) => 1
并不意味着v
的类型为int
这是编译器试图分析您的第一次尝试:
var varf1b = varc.F1(t => new { City = t.City }, (t, v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });
| | | | | | |
| | | | | | |
T2: C (varc) | | ? | ? |
| | | T1: new { string City, ? Bigstatus }
T3: new { string City } | |
T2: C |
T3: new { string City }
这是编译器试图分析你的第二次尝试:
var varf1b = varc.F1(t => new { City = t.City }, (C t, int v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });
| | | | | | |
| | | | | | |
T2: C (varc) | | T4: int | T4: int |
| | | T1: new { string City, int Bigstatus }
T3: new { string City } | |
T2: C |
T3: new { string City }
所以varf1b
的类型为:T1: new { string City, int Bigstatus }
,推理成功。
一个更简单的例子:
private static void GenericMethod<T1>(Func<T1, T1> func)
{
// ...
}
GenericMethod((a) => 1); // CS0411, `a` is not inferred from the body of the method.
GenericMethod<int>((a) => 1); // compiles
GenericMethod((int a) => 1); // compiles
答案 1 :(得分:-1)
我现在看到的答案是编译器没有可用于确定T4类型的信息。特别是,它无法检查表达式并从中推断出类型。
因此,为了解决这个问题,我们需要一个明确设置T4类型的参数。这是一种方法。
var varf1c = varc.F2(t => new { City = t.City }, 0, (t, v) => v + t.Status, (g, a) => new { City = g.City, Bigstatus = a });
public static T1 F2<T2, T3, T4, T1>(
this T2 s,
Func<T2, T3> g,
T4 i,
Func<T2, T4, T4> a,
Func<T3, T4, T1> r)
where T2 : class where T3 : class where T1 : class {
return null;
}
现在T4与文字参数0
相关联,编译器可以从中推断出int
的类型。