Ответ 1
Хорошо, я нашел способ воспроизвести эту ошибку, которую каждый может увидеть сам. И, прежде всего, программисты Microsoft, которые работают над Roslyn, которые должны это исправить. Достаточно было поворота в вопросе, что это проблема, характерная для библиотек COM-взаимодействия. Это подделано.
Я искал библиотеку типов, которая широко доступна с помощью метода, который имеет аргумент bool со значением по умолчанию true. Существует ровно один, каковы шансы:) Это метод SWbemQualifierSet.Add(), он принимает 3 логических аргумента, для которых все имеют значение по умолчанию.
Сначала я создал библиотеку interop, запустив эту команду из командной строки Visual Studio:
tlbimp C:\Windows\SysWOW64\wbem\wbemdisp.tlb
Создает библиотеку взаимодействия WbemScripting.dll. Затем написал небольшое тестовое приложение, которое вызывает этот метод, добавив библиотеку взаимодействия WbemScripting.dll в качестве ссылки:
class Program {
static void Main(string[] args) {
var obj = new WbemScripting.SWbemQualifierSet();
object val = null;
obj.Add("foo", ref val);
}
}
Остерегайтесь, что он фактически не запускается, нас интересует только тот код, который он генерирует. Глядя на сборку с помощью ildasm.exe:
IL_001e: ldstr "foo"
IL_0023: ldloca.s val
IL_0025: ldc.i4.1
IL_0026: ldc.i4.1
IL_0027: ldc.i4.1
IL_0028: ldc.i4.0
IL_0029: callvirt instance class WbemScripting.SWbemQualifier WbemScripting.ISWbemQualifierSet::Add(string,
object&,
bool,
bool,
bool,
int32)
Нет проблем, коды опций ldc.i4.1
передаются true. Оба Object Browser и IntelliSense правильно отображают true как значение по умолчанию.
Затем я запустил самую старую версию Tlbimp.exe, которую я смог найти на своей машине. Он генерирует совместимую с .NET 2.0.50727 сборку:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe" c:\windows\syswow64\wbem\wbemdisp.tlb
Восстановите тестовый проект, на этот раз он выглядит так:
IL_001e: ldstr "foo"
IL_0023: ldloca.s val
IL_0025: ldc.i4.0
IL_0026: ldc.i4.0
IL_0027: ldc.i4.0
IL_0028: ldc.i4.0
IL_0029: callvirt instance class WbemScripting.SWbemQualifier WbemScripting.ISWbemQualifierSet::Add(string,
object&,
bool,
bool,
bool,
int32)
Воспроизведение проблемы, обратите внимание, как ldc.i4.0
теперь передает false. Ваш точный сценарий. Все остальное ведет себя так, как должно, и Object Browser, и IntelliSense показывают false, как должны. Он просто не соответствует значению по умолчанию, указанному в библиотеке типа COM.
В любой другой версии Tlbimp.exe у меня есть версия SDK версии 7.1 и выше, создавая хороший код. Все они создают сборки .NET v4.0.
Характеристика ошибки не так проста. Я не вижу явного недостатка, когда я декомпилирую библиотеку "плохого" взаимодействия, он показывает, как объявляются правильные значения по умолчанию:
.method public hidebysig newslot virtual instance class WbemScripting.SWbemQualifier marshal(interface) Add([in] string marshal(bstr) strName, [in] object& marshal(struct) varVal, [in][opt] bool bPropagatesToSubclass, [in][opt] bool bPropagatesToInstance, [in][opt] bool bIsOverridable, [in][opt] int32 iFlags) runtime managed internalcall
{
.custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = { int32(2) }
.param [3] = bool(true)
.param [4] = bool(true)
.param [5] = bool(true)
.param [6] = int32(0)
.override WbemScripting.ISWbemQualifierSet::Add
}
Поэтому неудивительно, что Resharper не согласен с Object Browser и IntelliSense, он, безусловно, разбирает сам по себе и не полагается на интерфейсы метаданных .NET, поэтому показывает true как значение по умолчанию.
Поэтому я должен предположить, что Roslyn чувствителен к целевой версии исполнения. Другими словами, это только пойдет не так в старых библиотеках COM-взаимодействия, которые были созданы с инструментами старше .NET 4.0. В противном случае, не дико странно, С# не начинал поддерживать аргументы по умолчанию до v4, и были несовместимые способы указать значение по умолчанию. В худшем случае приходится использовать PIA, поставляемый поставщиком. Смягчение обстоятельств заключается в том, что значения по умолчанию, отличные от 0/false/null, не так уж и важны. Самый простой способ увидеть проблемную библиотеку - посмотреть на сборку с помощью ildasm.exe, дважды щелкните манифест. Верхняя строка:
// Metadata version: v2.0.50727
Это, безусловно, нарушение поведения для существующих проектов, которые были перестроены с помощью VS2015, сообщить об ошибке. Ссылка на этот Q + A, поэтому вам не нужно повторять все.
Обходной путь прост, просто заново создайте библиотеку interop с Tlbimp.exe, как я показал. Или удалите библиотеку interop и добавьте ссылку на COM-компонент, чтобы библиотека interop генерировалась "на лету" при ее создании. Если вы зависите от PIA от поставщика, вам придется попросить их об обновлении или правильной процедуре для создания новой библиотеки interop.