Warum sind drei Eigenschaften in DbParameterCollection in Referenzassemblys abstrakt, ansonsten jedoch virtuell?

68

Ich verschiebe ein Projekt von project.jsonin das neue csproj-Format und es enthält eine Klasse, die von abgeleitet ist DbParameterCollection. In meinem eigentlichen Projekt verwende ich Multi-Targeting, aber für die Zwecke dieser Frage müssen wir uns nur darum kümmern net45.

Der Compiler sagt mir, dass ich drei Eigenschaften überschreiben muss, die ich vorher nicht musste:

Wenn Sie diesen Dokumentationslinks (für .NET 4.5) folgen, werden Sie feststellen, dass alle Eigenschaften virtuell und nicht abstrakt sind. Wenn ich den Code nur durch Aufrufen erstelle, cscist alles in Ordnung. Nur wenn ich das .NET Core SDK verwende, stoße ich auf das Problem.

Hier ist ein Beispielcode, um das Problem zu reproduzieren:

Projektdatei:

<Project Sdk="Microsoft.NET.Sdk">    
  <PropertyGroup>
    <TargetFramework>net45</TargetFramework>
  </PropertyGroup>    
</Project>

C # -Code:

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;
}

Fehler:

DummyParameterCollection.cs (5,14): Fehler CS0534: 'DummyParameterCollection' implementiert das geerbte abstrakte Mitglied 'DbParameterCollection.IsSynchronized.get' nicht [c: \ Users \ skeet \ Test \ ParameterCollection \ ParameterCollection.csproj]
DummyParameterCollection.cs (5) 14): Fehler CS0534: 'DummyParameterCollection' implementiert kein geerbtes abstraktes Mitglied 'DbParameterCollection.IsFixedSize.get' [c: \ Users \ skeet \ Test \ ParameterCollection \ ParameterCollection.csproj]
DummyParameterCollection.cs (5,14): Fehler CS0534: 'DummyParameterCollection' implementiert kein geerbtes abstraktes Mitglied 'DbParameterCollection.IsReadOnly.get' [c: \ Users \ skeet \ Test \ ParameterCollection \ ParameterCollection.csproj]

Ich glaube, ich kenne die unmittelbare Ursache des Problems, aber nicht die Gründe, warum es so ist, oder die beste Problemumgehung.

Es sieht so aus, als ob das .NET Core SDK (und VS2017 beim Laden dieses Projekts) die Referenzassemblys verwendet. Wenn ich C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dllin Reflector öffne , werden die Eigenschaften ebenfalls als abstrakt angezeigt. Wenn ich dagegen öffne c:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll, werden die Eigenschaften als virtuell angezeigt.

Ich kann dies umgehen, indem ich die Eigenschaften überschreibe und einfach falsevon allen zurückkehre - aber ist das der beste Weg, um mit dieser Situation umzugehen? Gibt es darüber hinaus einen guten Grund, warum die Referenzbaugruppen in diesem Fall nicht mit den tatsächlichen Baugruppen (und der Dokumentation) übereinstimmen? Ich würde erwarten, dass die Referenzbaugruppen automatisch generiert werden, daher ist es seltsam, dass einige Dinge so falsch sind ...

Jon Skeet
quelle
Obwohl ich Reflector nicht habe, habe ich IL Disassembler verwendet, um die anderen DLLs im Ordner .NetFramework anzuzeigen. Alle Versionen bis v4.5 hatten diese Eigenschaften, da sie abstractab v4.5.1 virtuell waren. Warum unterscheiden sie sich? Ich kann nicht sagen, ohne zu raten.
Nkosi
Ich vermute also, dass sie virtualin den inkrementellen Updates nach Version 4.5 in den Referenzassemblys geändert wurden, was auch erklären würde, warum sie in der neuesten Version des Frameworks im Windows-Ordner enthalten sind. Ich verweise (kein Wortspiel beabsichtigt) auf diese Frage stackoverflow.com/questions/9701135/…
Nkosi
API-Dokumente von .net Framework <= 3.5 zeigen dies abstractebenfalls. Im .net-Standard ist es auch abstrakt. Die Referenzassembly in CoreFx für System.Data.Common zeigt sie jetzt auch als virtuelles github.com/dotnet/corefx/blame/master/src/System.Data.Common/…
Martin Ullrich
1
@SimonMourier: Sicher, ich habe keine Probleme damit - es ist nur die Tatsache, dass die Dokumente behaupten, dass die Eigenschaften virtuell sind, wenn sie abstrakt erscheinen project.json, und dass sie bei unserer Verwendung funktionieren , das ist seltsam ...
Jon Skeet
8
@ Somar: Bitte schlagen Sie keine Änderungen mehr vor, die die Fehlermeldungen unlesbar machen (indem Sie sich in einer sehr breiten Zeile befinden). Es ist perfekt lesbar wie es ist.
Jon Skeet

Antworten:

23

Die Referenzbaugruppen sind korrekt. In .NET Framework 4.5 waren diese Eigenschaften abstract. Sie wurden virtualin .NET Framework 4.5.1 geändert . Anscheinend haben Sie einen Dokumentationsfehler entdeckt.

Wie Sie wahrscheinlich bereits vermutet haben, ist der Unterschied zwischen den beiden beobachteten System.Data.dll-Assemblys darauf zurückzuführen, wie .NET Framework Referenzassemblys und Laufzeitassemblys trennt. Die Referenzbaugruppe in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dllspiegelt genau wider, was in der 4.5-Laufzeitversion von gewesen wäre System.Data.dll. Wenn Sie in der Lage sind, einen alten Computer zu erhalten, der noch nicht auf .NET Framework 4.5.1 aktualisiert wurde (viel Glück), werden Sie feststellen, dass die Laufzeitassembly in C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dlldie folgenden Eigenschaften aufweist abstract. .NET Framework-Upgrades sind vorhanden. Auf einem Computer, der auf .NET Framework 4.5.1 oder höher C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dllaktualisiert wurde , wurde er durch die aktualisierte Version ersetzt (mit virtualnicht abstractEigenschaften).

In net451Bezug auf Problemumgehungen: Kompilieren für oder Implementieren von Dummy-Methoden sind die besten Ansätze. Sie könnten andere Tricks ausführen, um gegen eine andere Version von System.Data.dll zu kompilieren, aber ich würde es nicht empfehlen

Ich konnte keine offizielle Dokumentation zu den API-Änderungen zwischen .NET Framework 4.5 und 4.5.1 oder eine Erklärung dafür finden, warum dies geändert wurde. Ich fand jedoch diesen Kommentar eines Mitglieds des Entity Framework-Teams: https: // bugzilla. xamarin.com/show_bug.cgi?id=29167#c0 .

Die folgenden (nicht unterbrechenden) Änderungen wurden an den System.Data-APIs in der Version .NET Framework 4.5.1 vorgenommen.

Das folgende Mitglied wurde hinzugefügt.

  • System.Data.Common.DbParameter.Precision
  • System.Data.Common.DbParameter.Scale
  • System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryCount
  • System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryInterval

Das folgende Mitglied wurde von abstrakt zu virtuell geändert.

  • 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
Natemcmaster
quelle
5
Danke für die Bestätigung. Ich bin mir immer noch nicht sicher, warum es früher gebaut wurde project.json, aber das ist eine andere Geschichte :)
Jon Skeet