类型推断是从右到左进行的吗?
Is type inference done from right to left?
考虑以下示例:
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
正好满足。
我的假设正确吗?
如果是这样,为什么要这样进行类型推断?我觉得从左到右更自然。
它完全不依赖于顺序。参数 p => p.Age
添加了约束,即无论 TValue
是什么,都必须是可以存储 int
的类型。这可能是 int
或它继承自的任何类型,例如 object
。当您传入 age
时,您是在说 TValue
必须是可以存储 object
的类型。然后它将选择满足所有这些约束的最派生类型,在本例中为 object
。如果您更改参数的顺序,也会发生同样的事情。
既不是从左到右,也不是从右到左。类型推断采用给定情况下可用的类型信息,并尝试找出可以替换的类型,以便它与所有相应的表达式兼容。这通常由最近的共同祖先满足。在您的情况下, int
和 object
都将 object
作为最近的共同祖先。但是,一般来说,由于接口的原因,分辨率可能会稍微复杂一些。
考虑以下示例:
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
正好满足。
我的假设正确吗?
如果是这样,为什么要这样进行类型推断?我觉得从左到右更自然。
它完全不依赖于顺序。参数 p => p.Age
添加了约束,即无论 TValue
是什么,都必须是可以存储 int
的类型。这可能是 int
或它继承自的任何类型,例如 object
。当您传入 age
时,您是在说 TValue
必须是可以存储 object
的类型。然后它将选择满足所有这些约束的最派生类型,在本例中为 object
。如果您更改参数的顺序,也会发生同样的事情。
既不是从左到右,也不是从右到左。类型推断采用给定情况下可用的类型信息,并尝试找出可以替换的类型,以便它与所有相应的表达式兼容。这通常由最近的共同祖先满足。在您的情况下, int
和 object
都将 object
作为最近的共同祖先。但是,一般来说,由于接口的原因,分辨率可能会稍微复杂一些。