Открытые общие аргументы типа нельзя вывести из использования
В этом вопросе, упоминая компилятор, я на самом деле ссылаюсь на компилятор Roslyn. Проблема возникает при использовании IntelliSense, который считается одним и тем же компилятором.
Для демонстрационных целей и полноты используются следующие классы (с использованием Visual Studio 2015 с С# 6.0 и .NET 4.6.1):
public class A
{
public IEnumerable<B> B { get; set; }
}
public class B
{
public IEnumerable<C> C { get; set; }
}
public class C { }
public class Helper<T> { }
Ниже приведен следующий метод расширения:
public static void FooBar<T1, T2>(
this Helper<IEnumerable<T1>> helper,
Expression<Func<T1, IEnumerable<T2>>> expression) { ... }
Компилятор способен вывести его при потреблении следующим образом:
Helper<IEnumerable<B>> helper = ...;
helper.FooBar(l => l.C); //T1 is B and T2 is C
Также смотрите этот перегруженный метод расширения:
public static void FooBar<T1, T2, T3>(
this Helper<T1> helper,
Expression<Func<T1, IEnumerable<T2>>> expression1,
Expression<Func<T2, IEnumerable<T3>>> expression2) { ... }
Компилятор НЕ может вывести T1
при вводе его следующим образом:
Helper<A> helper = ...;
helper.FooBar(l => l. //compiler/IntelliSense cannot infer that T1 is A
Этот пример скриншота будет описывать больше того, что я имею в виду, не имея возможности сделать вывод:
![введите описание изображения здесь]()
Также я получаю это сообщение об ошибке при наведении указателя мыши на метод расширения с помощью мыши (я заменил символы <
и >
[
и ]
соответственно, потому что StackOverflow не может форматировать их цитата):
Аргументы типа для метода FooBar [T1, T2] (этот помощник [IEnumerable [T1]], выражение [Func [T1, IEnumerable [T2]]]) не могут быть выведены от использования. Попробуйте явно указать аргументы типа.
Но когда он выполняется вручную, выполните следующие действия:
helper.FooBar(l => l.B, l => l.C); //compiler infers that T1 is A, T2 is B and T3 is C
компилятор счастлив.
Почему компилятор /IntelliSense (или функция автозаполнения Visual Studio) не вычисляет T1
и не хочет, чтобы я явно указывал аргументы типа при вводе?
Обратите внимание, что если я опускаю IEnumerable<>
всюду в своих примерах, компилятор может с радостью сделать вывод во время ввода.
Компилятор также счастлив после ввода вручную l => l.B
. Затем он знает T1
is A
, поэтому вы можете выразить последний аргумент с помощью IntelliSense.
Ответы
Ответ 1
Если я правильно вас понял, все работает как ожидалось для меня в VS2013:
Ваш первый случай:
![]()
Ваш второй случай:
![]()
Я начинаю вводить l.
, и IntelliSense показывает мне, что l
имеет свойство B
, которое можно использовать. Поэтому, если я прав, а правильно отображается в VS2013, тогда как не выводит в VS2015, тогда это определенно ошибка в VS2015 IntelliSense, о которой можно сообщить в Microsoft.
Ответ 2
Я нашел ваш вопрос интересным, и поскольку я использую VS 2015, я думал, что смогу попробовать и его. Я получил ту же ошибку, что и вы, поэтому я думаю, что это может быть ошибка VS, поскольку в других версиях она работает правильно.
Вот моя ошибка:
![введите описание изображения здесь]()
И у меня также нет предложений по CTRL + SPACE.
EDIT:
Аналогичную ошибку можно увидеть здесь.
Итак, поскольку в более старых версиях VS это работает, то именно по этой причине его можно считать ошибкой.
Ответ 3
Как я уже сказал, у меня была та же проблема. (И здесь отчет об ошибке)
Это не связано с выражениями или IEnumerable.
Вот упрощенный пример
using System;
namespace ConsoleApplicationExpressionTree
{
public static class Extentions
{
static void Main() { }
static void AMethod(string[] args)
{
SetValue(new Customer(), e => e.Name /*type here */, "TheName");
}
public static void SetValue<TEntity, TProperty>(TEntity instance, Func<TEntity, TProperty> expression, TProperty newValue)
{
}
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
}
Я только заметил, что если вы удалите третий аргумент из метода, который он работает!!!
using System;
namespace ConsoleApplicationExpressionTree
{
public static class Extentions
{
static void Main() { }
static void AMethod(string[] args)
{
SetValue(new Customer(), e => e.Name /*type here */);
}
public static void SetValue<TEntity, TProperty>(TEntity instance, Func<TEntity, TProperty> expression)
{
}
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
}
Итак, если вам очень повезло, вы можете исправить свой текущий пример, изменив параметры.
Если нет, вам просто придется ждать MS, чтобы исправить это...