我有一个关于编译器在使用泛型和扩展方法时如何推断类型的问题。提出问题的最简单方法是先显示一些代码......
我有一个看起来有点像这样的ViewModelBase类(包含所有不相关的内容)。基本上我的NavigationService类每次应用程序进入与之链接的View时都会调用NavigatingTo方法。
此类的继承者可以调用Return委托将数据传递回调用者。
public abstract class ViewModelBase<TContext, TReturn>
{
public Action<TReturn> Return { get; set; }
public abstract void NavigatingTo(TContext context);
}
然后我有一个继承ViewModelBase的测试ViewModel:
public class TestViewModel : ViewModelBase<int, bool>
{
public override void NavigatingTo(int context)
{
// do stuff here
}
}
接下来,我有一个通用的NavigationCommand类,它接受像这样的ViewModelBase:
public class NavigationCommand<TViewModel>
{
public TViewModel ViewModel { get; set; }
public NavigationCommand(TViewModel viewModel)
{
this.ViewModel = viewModel;
}
}
最后我有一个NavigationCommand类的扩展方法,可以向它添加一个Navigate方法。我的目标是通过声明我的Navigate方法需要带有TContext和TReturn的ViewModelBase,编译器应该能够推断出实际使用的类型:
public static class NavigationExtensions
{
// I actually pass in a INavigationService here too, but I have left that out to
// make it easier to read...
public static void Navigate<TViewModel, TContext, TReturn>(
this NavigationCommand2<TViewModel> viewModel,
TContext context,
Action<TReturn> returnAction)
where TViewModel : ViewModelBase<TContext, TReturn>
{
// actual implementation omitted
}
}
好的,现在在我的ApplicationController类中,我执行以下操作:
var vm = new TestViewModel();
var cmd = new NavigationCommand2<TestViewModel>(vm);
int clientID = 1;
Action<bool> returnAction = success =>
{
Console.WriteLine(success.ToString());
};
cmd.Navigate(clientID, returnAction);
它可以工作,如果你尝试传入一个不正确的类型,你在构建时会遇到编译器错误。但是Intellisense不会提示您输入正确的类型。
所以我的问题:有没有办法重写扩展方法,或者我的NavigationCommand类或ViewModel等,以便Intellisense实际上提示我使用正确的类型?
目前所有的Intellisense都给了我这个:
(extension void) NavigateCommand<TestViewModel>.Navigate(TContext context, Action<TReturn> returnAction)
当我想要的是这个:
(extension void) NavigateCommand<TestViewModel>.Navigate(int context, Action<bool> returnAction)
答案 0 :(得分:1)
解决此问题的方法之一是将TContext和TReturn类型参数传播到NavigationCommand,因此其声明将如下所示:
public class NavigationCommand<TViewModel, TContext, TReturn> where TViewModel:ViewModelBase<TContext, TReturn>
但它使命令初始化更加冗长(因为TestViewModel
类型实际上已包含有关TContext
和TReturn
实际类型的信息):
var cmd = new NavigationCommand<TestViewModel, int, bool>(vm);
实际上,您发布的实现已经是类型安全的,并且不允许您传递不正确类型的参数(假设string
而不是int
)。唯一的问题是Intellisense因某种原因无法正确推断出类型。