考虑以下示例:
public class Person
{
public int Age { get; set; }
}
public class Builder<TSource>
{
public Builder<TSource> WithValue<TValue>(Func<TSource, TValue>, TValue value)
{
// ...
}
}
这两行可以正常运行:
Builder<Person> builder = new Builder<Person>();
builder.WithValue(p => p.Age, 20);
但这些也是如此:
Builder<Person> builder = new Builder<Person>();
object age = "20"; // <-- string value
builder.WithValue(p => p.Age, age);
类型推断不能像我期望的那样在后一个例子中起作用。
如果我指定表达式p => p.Age
,即Func<Person, int>
,我希望第二个参数被约束为int
类型。然而,我能够通过object
就好了。
我猜这是因为类型推断是从右到左完成的。也就是说,TValue
参数被称为object
,然后我的Func<TSource, TValue>
表达式被约束为Func<Person, object>
,p => p.Age
满足要求。
我的假设是否正确?
如果是这样,为什么类型推断是这样做的?我觉得从左到右更自然。
答案 0 :(得分:5)
根本不依赖于订单。参数TValue
正在添加约束,即int
必须是可以存储int
的类型。这可以是object
或其继承的任何类型,例如age
。当您传递TValue
时,您说object
必须是可以存储object
的类型。然后,它将选择满足所有这些约束的派生类型,在本例中为{{1}}。如果你改变了参数的顺序,就会发生同样的事情。
答案 1 :(得分:1)
既不是从左到右,也不是从右到左。类型推断采用给定情况下可用的类型信息,并尝试确定可以替换的类型,以便它与所有相应的表达式兼容。这通常由最近的共同祖先满足。在您的情况下,int
和object
都有object
作为最近的共同祖先。但是,一般来说,由于接口,分辨率可能会有点复杂。