Подтвердить что ты не робот

Почему три свойства в аббревиатуре 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 из всех них - но это лучший способ справиться с этой ситуацией? Кроме того, есть ли веская причина, почему ссылочные сборки не соответствуют реальным сборкам (и документации) в этом случае? Я бы ожидал, что эталонные сборки будут автогенерированы, поэтому для некоторых вещей это нечетно...

4b9b3361

Ответ 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