这个问题是关于什么时候,不需要包含泛型类型规范参数。它有点冗长,所以请耐心等待。
如果您有以下(人为的)课程......
public abstract class UserBase
{
public void DoSomethingWithUser() { }
}
public class FirstTimeUser : UserBase
{
/* TODO: some implementation */
}
以下方法......
private static void DoThingsWithUser<TUser>(TUser user) where TUser : UserBase
{
user.DoSomethingWithUser();
}
可以在必须指定类型参数TUser
...
var user = new FirstTimeUser();
DoThingsWithUser<FirstTimeUser>(user);
DoThingsWithUser(user); // also valid, and less typing required!
到目前为止,非常好。
但是,如果你再添加一些(再次,人为的)类......
public abstract class UserDisplayBase<T> where T : UserBase
{
public T User { get; protected set; }
}
public class FirstTimeUserDisplay : UserDisplayBase<FirstTimeUser>
{
public FirstTimeUserDisplay()
{
User = new FirstTimeUser();
}
}
一种方法......
private static void DoThingsWithUserDisplay<TDisplay, TUser>(TDisplay userDisplay)
where TDisplay : UserDisplayBase<TUser>
where TUser : UserBase
{
userDisplay.User.DoSomethingWithUser();
}
调用此方法时,必需包含类型参数...
var userDisplay = new FirstTimeUserDisplay();
DoThingsWithUserDisplay<FirstTimeUserDisplay, FirstTimeUser>(userDisplay); // Type arguments required!
如果未指定类型参数,则会出现编译器错误
无法从用法推断出方法'DoThingsWithUserDisplay(TDisplay)'的类型参数。尝试明确指定类型参数。
我认为编译器应该/可能足够智能来解决这个问题......或者有一个微妙的原因,为什么不呢?
答案 0 :(得分:2)
由于编译器正在分析要推断的类型,因此在查看DoThingsWithUserDisplay(userDisplay);
它发现TDisplay
必须是FirstTimeUserDisplay
类型,这很好。然后约束表明TDisplay
必须从UserDisplayBase<TUser>
继承。
由于它不知道TUser
的类型,因此无法确定FirstTimeUserDisplay
是否继承自UserDisplayBase<TUser>
,而且它也无法推断TUser
参数应该通用UserDisplayBase<TUser>
中的任何类型。
编辑: 顺便提一下,您可以使用带变体的接口获取所需的类型推断。在这种情况下,接口定义提供了足够的继承信息,以便满足约束条件。
public abstract class UserDisplayBase<T> : IUserDisplayBase<T>
where T : UserBase
{
public T User { get; protected set; }
}
public interface IUserDisplayBase<out T>
where T : UserBase
{
T User { get; }
}
private static void DoThingsWithUserDisplay<TDisplay>(TDisplay userDisplay)
where TDisplay : IUserDisplayBase<UserBase>
{
userDisplay.User.DoSomethingWithUser();
}
可以用
调用var userDisplay = new FirstTimeUserDisplay();
DoThingsWithUserDisplay(userDisplay);