Обобщения и методы расширения - как IntelliSense выводит типы? - PullRequest
1 голос
/ 12 сентября 2011

У меня есть вопрос о том, как компилятор выводит типы при использовании обобщенных методов и методов расширения. Самый простой способ задать мой вопрос - сначала показать код ...

У меня есть класс ViewModelBase, который выглядит примерно так (с удалением всего, что не имеет значения). По сути, мой класс NavigationService вызывает метод NavigatingTo каждый раз, когда приложение переходит в представление, с которым оно связано.

Наследники этого класса могут вызывать делегат Return для передачи данных вызывающей стороне.

public abstract class ViewModelBase<TContext, TReturn>
{
    public Action<TReturn> Return { get; set; }

    public abstract void NavigatingTo(TContext context);
}

Тогда у меня есть тестовая модель ViewModel, которая наследует ViewModelBase:

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 требуется ViewModelBase с TContext и TReturn, компилятор должен иметь возможность определить, какие типы фактически должны использоваться:

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)

1 Ответ

1 голос
/ 12 сентября 2011

Одним из способов решения этой проблемы является распространение параметров типа 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, которая по какой-то причине не может правильно определить тип.

...