Почему три свойства в аббревиатуре DbParameterCollection в ссылочных сборках, но виртуальные в противном случае?
Я перемещаю проект из project.json
в формат csproj нового стиля и включает класс, полученный из DbParameterCollection
, В моем реальном проекте я использую мультитаргетинг, но для целей этого вопроса нам нужно только заботиться о net45
.
Компилятор говорит мне, что мне нужно переопределить три свойства, которые мне не нужно:
Если вы следуете этим ссылкам документации (которые относятся к .NET 4.5), вы увидите, что все свойства являются виртуальными, а не абстрактными. Если я создаю код, просто позвонив csc
, все будет хорошо... это только при использовании .NET Core SDK, с которым я столкнулся с проблемой.
Здесь пример кода для воспроизведения проблемы:
Файл проекта:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net45</TargetFramework>
</PropertyGroup>
</Project>
Код С#:
using System;
using System.Collections;
using System.Data.Common;
public class DummyParameterCollection : DbParameterCollection
{
public override int Count => 0;
public override object SyncRoot => null;
public override void Remove(object value) {}
public override void RemoveAt(int index) {}
public override void RemoveAt(string parameterName) {}
public override int Add(object value) => 0;
public override void Insert(int index, object value) {}
public override void AddRange(Array values) {}
public override void Clear() {}
public override bool Contains(object value) => false;
public override bool Contains(string value) => false;
public override void CopyTo(Array array, int index) {}
public override int IndexOf(object value) => -1;
public override int IndexOf(string parameterName) => -1;
protected override DbParameter GetParameter(int index) => null;
protected override DbParameter GetParameter(string parameterName) => null;
protected override void SetParameter(int index, DbParameter value) {}
protected override void SetParameter(string parameterName, DbParameter value) {}
public override IEnumerator GetEnumerator() => null;
}
Ошибки:
DummyParameterCollection.cs(5,14): ошибка CS0534: "DummyParameterCollection" не реализует унаследованный абстрактный элемент "DbParameterCollection.IsSynchronized.get" [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
DummyParameterCollection.cs(5,14): ошибка CS0534: "DummyParameterCollection" не реализует унаследованный абстрактный элемент "DbParameterCollection.IsFixedSize.get" [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
DummyParameterCollection.cs(5,14): ошибка CS0534: "DummyParameterCollection" не реализует унаследованный абстрактный элемент "DbParameterCollection.IsReadOnly.get" [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
Я считаю, что я знаю непосредственную причину проблемы, но не причины, почему это так, или лучшее обходное решение.
Похоже, что .NET Core SDK (и VS2017 при загрузке этого проекта) использует эталонные сборки. Если я открываю C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll
в Reflector, это показывает, что свойства также являются абстрактными. Если я открываю c:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
, это показывает, что свойства являются виртуальными.
Я могу обойти это, переопределив свойства и просто вернув false
из всех них - но это лучший способ справиться с этой ситуацией? Кроме того, есть ли веская причина, почему ссылочные сборки не соответствуют реальным сборкам (и документации) в этом случае? Я бы ожидал, что эталонные сборки будут автогенерированы, поэтому для некоторых вещей это нечетно...
Ответы
Ответ 1
Исходные сборки верны. В .NET Framework 4.5 эти свойства были abstract
. Они были изменены на virtual
в .NET Framework 4.5.1. Похоже, вы обнаружили ошибку в документации.
Как вы, наверное, уже догадались, разница между двумя сборками System.Data.dll, которые вы наблюдаете, объясняется тем, как .NET Framework разделяет сборки ссылок и сборки времени выполнения. Эталонная сборка в C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll
точно отражает то, что было бы в версии 4.5 времени исполнения System.Data.dll
. Если вы можете получить старую машину, которая еще не обновлена до .NET Framework 4.5.1 (удачи), вы обнаружите, что сборка времени выполнения в C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
имеет эти свойства как abstract
..NET Framework обновляется на месте. На машине, обновленной до .NET Framework 4.5.1 или новее, C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
был заменен обновленной версией (с virtual
, а не abstract
, свойствами.)
Что касается обходных путей: вместо компиляции для net451
или реализации фиктивных методов - наилучшие подходы. Вы могли бы сделать другие трюки для компиляции с другой версией System.Data.dll, но я бы не рекомендовал ее
Я не смог найти официальную документацию по изменениям API между .NET Framework 4.5 и 4.5.1 или объяснение причин, почему это было изменено, однако я нашел этот комментарий от члена команды Entity Framework: https://bugzilla.xamarin.com/show_bug.cgi?id=29167#c0.
Следующие изменения (non-break) были внесены в API System.Data в выпуске .NET Framework 4.5.1....
Добавлен следующий элемент.
- System.Data.Common.DbParameter.Precision
- System.Data.Common.DbParameter.Scale
- System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryCount
- System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryInterval
Следующий член был изменен с абстрактного на виртуальный.
- System.Data.Common.DbDataReader.Close
- System.Data.Common.DbDataReader.GetSchemaTable
- System.Data.Common.DbParameter.SourceVersion
- System.Data.Common.DbParameterCollection.IsFixedSize
- System.Data.Common.DbParameterCollection.IsReadOnly
- System.Data.Common.DbParameterCollection.IsSynchronized