通用类型规范参数 - 有时是可选的,但并非总是如此
Generic type specification arguments - sometimes optional, but not always
这个问题是关于何时需要和不需要包含泛型类型规范参数的。有点长,还请大家多多包涵
如果你有以下(人为的)类...
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!
如果你不指定类型参数,你会得到一个
的编译器错误
The type arguments for method 'DoThingsWithUserDisplay(TDisplay)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
我 认为 编译器 should/could 足够聪明来解决这个问题......或者有什么微妙的原因为什么不呢?
由于编译器正在分析要推断的类型,因此在查看 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);
这个问题是关于何时需要和不需要包含泛型类型规范参数的。有点长,还请大家多多包涵
如果你有以下(人为的)类...
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!
如果你不指定类型参数,你会得到一个
的编译器错误The type arguments for method 'DoThingsWithUserDisplay(TDisplay)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
我 认为 编译器 should/could 足够聪明来解决这个问题......或者有什么微妙的原因为什么不呢?
由于编译器正在分析要推断的类型,因此在查看 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);