Примечание: это была ошибка в Roslyn, исправленная в Visual Studio 2017.
Visual Studio 2015 не может определять типы лямбда-параметров в таких методах, как Enumerable.Join
. Рассмотрим следующий код:
public class Book
{
public int AuthorId { get; set; }
public string Title { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
}
public static void NoIntellisenseInEnumerableJoin()
{
IEnumerable<Book> books = null;
IEnumerable<Author> authors = null;
//Intellisense fails on both 'book => book.AuthorId' and 'author => author.Id'
var test = books.Join(authors, book => book.AuthorId, author => author.Id, (book, author) => new { book, author });
}
Когда я набираю book => book.
, ничего не появляется. Когда я нависаю над book
, Intellisense называет его (parameter) ? book
.
Что я пытался исправить?
-
devenv.exe /resetuserdata
- Удаленные .suo,.vs и т.д., хотя это происходит в каждом проекте всем в моей команде.
- Прошли все девять шагов в этом списке c-sharpcorner, за исключением пары, которая, похоже, не применяется к Visual Studio 2015.
- Отправлено "нахмурившись"
Дополнительная информация
- Проблема возникает в равной степени с
Func<>
иExpression<Func<>>
- Intellisense, похоже, работает нормально (за исключением абсурдного времени обработки JavaScript, что является другой историей...)
- Эта проблема возникает только в 2015 году. Пример хорошо работает в 2010, 2012 и 2013 годах, хотя один из моих товарищей по команде недавно начал иметь очень похожую проблему с 2013 годом вокруг обновления 4.
- Я использую Visual Studio Enterprise 2015 Version 14.0.24620.00 Update 1, но та же проблема возникла до того, как я установил обновление 1.
- Проблема не возникает во всех подобных случаях. Например,
books.Select(book => book.
работает правильно. - Если я вернусь после написания инструкции, VS знает, что это
book
и дает мне правильные варианты. Это приводит к интересной работе, когда я могу напечататьbooks.Join(authors, , , )
, а затем заполнить пробелы и снова получить intellisense. - Кажется, что это связано с выводом типичных типов. См. Приведенный ниже пример дома.
Wrapper<Book>.Combine(authors, book => book.AuthorId, author => author.Id
работает дляbook
, но не дляauthor
. Типbook
исходит из общего аргумента класса, но типauthor
исходит из метода. - Удивительно, но явное указание типов не всегда устраняет проблему.
- Сначала я думал, что проблема заключается в том, что
Join
имеет несколько переопределений, но проблема возникает в приведенном ниже примере ниже без переопределений.
Пример, выращенный в домашних условиях
public class Wrapper<TInner>
{
public void Combine<TOuter, TKey>(Wrapper<TOuter> outer, Func<TInner, TKey> innerKey, Func<TOuter, TKey> outerKey)
{ }
public void ThisWorks<TOuter>(Wrapper<TOuter> outer, Func<TInner, int> innerKey, Func<TOuter, int> outerKey)
{ }
}
public static class WrapperExtensions
{
public static void CombineExt<TInner, TOuter, TKey>(this Wrapper<TInner> inner, Wrapper<TOuter> outer,
Func<TInner, TKey> innerKey, Func<TOuter, TKey> outerKey)
{ }
public static void ThisAlmostWorks<TInner, TOuter>(this Wrapper<TInner> inner, Wrapper<TOuter> outer,
Func<TInner, int> innerKey, Func<TOuter, int> outerKey)
{ }
}
public static class NoIntellisenseExamples
{
public static void NoIntellisenseInSimplerCase()
{
var books = new Wrapper<Book>();
var authors = new Wrapper<Author>();
//Intellisense fails on 'author => author.Id' but works for the book lambda.
books.Combine(authors, book => book.AuthorId, author => author.Id);
new Wrapper<Book>().Combine<Author, int>(authors, book => book.AuthorId, author => author.Id);
//Intellisense fails on both 'book => book.AuthorId' and 'author => author.Id' in both of the following:
books.CombineExt(authors, book => book.AuthorId, author => author.Id);
WrapperExtensions.CombineExt(books, authors, book => book.AuthorId, author => author.Id);
//Intellisense works perfectly here.
books.ThisWorks(authors, book => book.AuthorId, author => author.Id);
//Intellisense fails on 'book => book.AuthorId' but works for 'author => author.Id'
books.ThisAlmostWorks(authors, book => book.AuthorId, author => author.Id);
}
}