Тип вывода - это все или ничего. Если заданы какие-либо аргументы типа, все они должны быть указаны. Таким образом, вам нужен способ либо:
- позволяют
TView
быть выведено из аргумента
- избежать необходимости
TView
в качестве аргумента типа
- избежать необходимости
T0
и T1
в качестве аргументов типа
- найти путь разделить аргументы типа
Вы можете позволить TView
быть выведены путем передачи функции фабричной указать TView
«s тип:
public static void Navigate<TView, T0, T1>(Func<TView> factory, T0 arg0, T1 arg1)
where TView : ViewBase<T0, T1> {
var view = factory();
view.Initialize(arg0, arg1);
// ...
}
Теперь, вместо Navigate<DerivedView>("Joe", 42)
, называют Navigate(() => new DerivedView(), "Joe", 42)
.
Примечание: для этого потребуются типы arg0
и arg1
, чтобы точно соответствовать TView
. Неявные преобразования не будут работать. Если представление получено от ViewBase<int, object>
, а arg1
- "Hello"
, то T1
будет выведено как тип string
, вызывая сообщение об ошибке компилятора.
Поскольку вы не использовать TView
«s типа, кроме как построить экземпляр, вы можете избежать TView
в качестве аргумента типа, используя функцию заводской тоже:
public static void Navigate<T0, T1>(Func<ViewBase<T0, T1>> factory, T0 arg0, T1 arg1) {
var view = factory();
view.Initialize(arg0, arg1);
// ...
}
Это также позволяет избежать проблем с неявными преобразованиями, поскольку и T0
, и T1
могут быть выведены из factory
.
Как избежать T0
и T1
в качестве аргументов типа: имя Initialize
несколько предполагает, что его функциональные возможности могут принадлежать в конструкторе. Если это так, вы можете тривиально избегать их как аргументов типа, оставив конструкцию вызывающему: фабричная функция может быть () => new DerivedView("Joe", 42)
. Однако, если это не относится к вам, если вам действительно нужен отдельный метод Initialize
, который вызывается Navigate
, то я не вижу никаких параметров, которые избегают T0
и T1
как аргументы типа.
Наконец, разделив аргументы типа:
public static class Navigator {
public static WithViewHelper<TView> WithView<TView>()
where TView : new() => new WithViewHelper<TView>();
public struct WithViewHelper<TView> where TView : new() { }
}
public static class NavigatorExtensions {
public static void Navigate<TView, T0, T1>(this Navigator.WithViewHelper<TView> withViewHelper, T0 arg0, T1 arg1)
where TView : ViewBase<T0, T1>, new() {
var view = new TView();
view.Initialize(arg0, arg1);
}
}
Это позволяет вызывать Navigator.WithView<DerivedView>().Navigate("Joe", 42)
. Для этого требуется Navigate
, поскольку в противном случае ограничение общего типа не может быть выражено. У него снова возникают проблемы с неявными преобразованиями: Navigator.WithView<DerivedView>().Navigate(null, 42)
не сможет скомпилировать: хотя null
конвертируется в string
, компилятор не поймет, что T0
должен быть string
.
родовых параметров для 'Initialize' является затенением параметров класса уровня' 'ViewBase так что вы, вероятно, хотите, чтобы удалить их. Затем вы можете изменить «Навигация» на «Навигация» (..), где TView: ViewBase , new() '. –
Lee
Вы правы, это была ошибка при написании сообщения. У меня нет общих аргументов в моем коде. Во всяком случае .. Это не настоящая проблема, просто нужно дать какой-то контекст. –