【问题标题】:Generics and Extension Methods - how does IntelliSense infer types?泛型和扩展方法 - IntelliSense 如何推断类型?
【发布时间】:2011-11-15 04:56:12
【问题描述】:

我有一个关于编译器在使用泛型和扩展方法时如何推断类型的问题。问我问题的最简单方法是先显示一些代码...

我有一个看起来有点像这样的 ViewModelBase 类(去掉了所有不相关的内容)。基本上,每次应用程序转到与其链接的视图时,我的 NavigationService 类都会调用 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)

【问题讨论】:

    标签: c# wpf generics extension-methods intellisense


    【解决方案1】:

    解决此问题的方法之一是将 TContext 和 TReturn 类型参数传播到 NavigationCommand,因此其声明将如下所示:

    public class NavigationCommand<TViewModel, TContext, TReturn> where TViewModel:ViewModelBase<TContext, TReturn>
    

    但是它使命令初始化更加冗长(因为TestViewModel类型实际上已经包含了TContextTReturn实际类型的信息):

    var cmd = new NavigationCommand<TestViewModel, int, bool>(vm);
    

    实际上,您发布的实现已经是类型安全的,并且不允许您传递不正确类型的参数(比如说string 而不是int)。唯一的问题是 Intellisense 由于某种原因无法正确推断类型。

    【讨论】:

    • 谢谢安德鲁。我真的很想避免在 NavigationCommand 中显式定义类型,因为正如您所说的那样,它很冗长,但如果上下文或返回类型发生变化,您还必须在其中进行更改。关于为什么 Intellisense 不接受这个的任何想法?
    • 再次感谢安德鲁。在发布这个问题之前,我实际上已经阅读了该帖子和博客,但觉得我的情况略有不同。在博客中,Eric 似乎在讨论为什么编译器在某些情况下无法推断类型,因此会引发编译时错误。在我的情况下,编译器正确识别类型,并且不会让您使用与视图模型中定义的类型不兼容的类型的变量。问题是 IntelliSense 无法识别它。谢谢你的时间。我想我会改变我的方法并保持不变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-11
    相关资源
    最近更新 更多